#Arduino Help
1 messages · Page 5 of 1
But well that's more or less my plan of I'mma learn this then that then I will he comfortable enough to stop jumping from languages
And actually do something
nothing wrong with that (as long as you are not neglecting other things)
Tho I liked studying electronics to some extent and I seem to have a thing for embedded systems, low level
I mean I feel so excited to buy the raspberry Pi pico for some reason
But also seeing the app made in rust and so thought hey maybe this is fun but I have to learn other stuff before
There's no project in particular I feel like doing
Embedded is very fun. That's why I am a computer engineer. Mixing electronics and software is just 
And if we speaking of embedded projects
I can't afford them.
I saw a nixie tubes clock project and thought
yeah, that's the downside sadly
Yeah it would be really cool to do that
And then he started listing prices
And well
My go to project for people without projects is a NES emulator
2 reactions: Thats to complicated, that sounds interesting
Here I will do engineer in systems or smth like that because it's the only career that has programming I know aside from computer scientists but I think maybe cs it's not what I want to do so
I never played the nes so .. .
I wanted before to do a WhatsApp bot
But know I wouldn't have use for it
Emulators are fun because it's electronics, but in software
Well tomorrow we could talk also about stuff like that I would really like to say I wanna program this and focus on that so I get good I use what I learn and not that far in the future I would know enough to do it alone or even earn money from it
I way wanna try doing apps or webs with rust and I think tauri or dino that made my backend web assembly idk
I really need to know HTML css and js
Tho I heard css it's a enormous pain
custom!{Jsr, {Absolute, cpu,
_0, cpu.read_next(),
_1, {cpu.store_to_temp(); cpu.read_from(cpu.stack())},
_2, {
cpu.write_to(cpu.stack(), (((cpu.internal.pc + 1) >> 8) & 0xFF) as u8);
cpu.internal.s = cpu.internal.s.wrapping_sub(1);
},
_3, {
cpu.write_to(cpu.stack(), ((cpu.internal.pc + 1) & 0xFF) as u8);
cpu.internal.s = cpu.internal.s.wrapping_sub(1);
},
_4, cpu.read_next(),
_5, {
cpu.fetch_next_from(cpu.calc_address())
}
}}
My really bad macro for my NES emulator that is half put together 
it can be, depends on what you are doing
I want to use rust in the other stuff
It would be could if I had something I said
Hey it wouod come in handy
Or smth
yep
As I said idk like programming a bot
Its 12:31 
Pff
It's 3:32 and I have school (?
I will go to sleep because I should've some hours ago
I will mention that
We are really close to the
First milestone
Sleep!
That is getting the base functionality of the project and getting to last component in the current state of the project (it isn't like there will be much more)
Lcd is just left two stuff
And the other two stuff as I stated it should be easy
Actually maybe
When we get to the keyboard (tomorrow I hope)
Take me to process of finding the library in crate. Io
(I love how Lux keeps popping into the discussion but doesn't say anything
)
Nah i was gonna give some impressions of webdev in rust but i am slow to type and the discussion moved too quickly
I also loved that when I saw it and did ladder, I enjoyed ladder reaaaally much and I thought of landing a first job in an offer I saw of looking for technician in electronics, no experience, desired c/c++ knowledge and they were a plc company or I would basically work with them idk
Say it, tho I know nothing of web development yet(?
plc?
Tomorrow we gotta talk about it(?
Now it's too late to right my usual Bible
Sleep 💤
After lux impression ima go sleep
Well since I will only have 4 hours of sleep I better go now and read it tomorrow- anyways no one else writes here, guten natch
rust is strong as a server language, with a lot of powerful library/framework options
on the client side, it's not quite as mature yet; if you're using it to do heavy lifting for computing it's good, or if you're using it for a game that's decently supported; if you're using it for UI (e.g. (v)DOM manipulation), then there are usable options (yew is the big one here, afaict), but said options aren't at the point where they're production-ready yet.
Another note, that may or may not be relevant depending on your prior experiences/expectations, is that rust's compile times mean that your iteration cycle (how long it takes to change code -> compile code -> see results -> repeat) is limited to the speed at which your project compiles, which can be painful as project size grows, especially for lower-spec computers, compared to for example javascript, php, python, whatevs, that are interpreted (although js build tools are a whole hassle of their own)
Anyway, that's my little spiel; not sure if anything there is useful but just explore! what you're interested in
Oh my days, sleep!
@coral geyser it didn't work :(
Idk why
I don't know what link.exe it's and where it may be
Ans gat of visual c++ option maybe is something we forgot the fact the rust needed some tool fr c++ or smth like that
PS C:\Users\Taller03> cd
PS C:\Users\Taller03> cd D:\
PS D:\> cd rust_toolchain
PS D:\rust_toolchain> .\busybox.exe ash setup_rust_arduino.sh
Directory of rust toolchain: D:/rust_toolchain
Starting configured ash shell, run 'exit' to exit the shell.
D:/rust_toolchain $ cd ..
D:/ $ cd rust_lcd
D:/rust_lcd $ cargo check
Compiling compiler_builtins v0.1.73
Compiling core v0.0.0 (D:\rust_toolchain\.rustup\toolchains\nightly-2022-06-13-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core)
Compiling proc-macro2 v1.0.42
Compiling rustversion v1.0.8
Compiling quote v1.0.20
Compiling unicode-ident v1.0.2
Compiling semver-parser v0.7.0
Compiling syn v1.0.98
error: linker `link.exe` not found
|
= note: program not found
note: the msvc targets depend on the msvc linker but `link.exe` was not found
note: please ensure that VS 2013, VS 2015, VS 2017, VS 2019 or VS 2022 was installed with the Visual C++ option
error: could not compile `proc-macro2` due to previous error
warning: build failed, waiting for other jobs to finish...
error: could not compile `compiler_builtins` due to previous error
error: could not compile `quote` due to previous error
error: could not compile `syn` due to previous error
error: could not compile `rustversion` due to previous error
D:/rust_lcd $
Just in case
I copied the error to text
I'm finally home btw
Oh, the proc macros needed to be recompiled. I forgot about those ones
Well after me having tea time and all
Based on this error
We can now make it work
Tho this was a borrowed pendrive, now I kinda have one that can be mine so
I will do that all over but knowing what to do so anyways I want to do it to this one that already has the other stuff
What you will need is a copy of cygwin with gcc on the USB drive. That will replace the Microsoft build tools
.. .
We better see it with the computer then and all because no clue
But does this have to do with C++ built tools?
Yeah, when rustc is compiling code there can be proc macros that are compiled and run during the compilation. It failed because it couldn't build those proc macros
In some minutes I'm available to do it if you are
Ok I'm back @coral geyser are you?
I have good news about the project, it finally has a Max limit
Up until know I would finish doing what I was supposed to do and he will tell ok how about this know
now*
But now, finally there's a limit when I do up until a point and it's finally done
And it isn't that far away
After RFID, two sensors which I could guess they are easy to work with and it's done
And finally I can move on do other stuff without a time limit or stuff
@coral geyser are you available? Or later ofc also
Yeah I have some time
Today i have again the python class
Today we finally use vs code
Well anyways so
The idea is the following
We add what's missing to the usb
But more so because so I know what I need there
Because actually I have to move all again to another pendrive but, I would know the steps so I wouod do it alone when I need to
And then we'll finish the lcd
And if my chance the lcd didn't took long go to the matricial keyboard
Well I'mma go to the bathroom and turn on the computer
Ok done
And I plugged in the usb
What's left to get to the USB?
Download https://www.cygwin.com/ we will use it to get a replacement for link.exe
When you installed rust you had to install the Microsoft build tools right?
Ah yeah Likely
Its in that
But that one requires admin privileges to install
Oh
Installing Cygwin: setup-x86_64.exe
So then I go to downloads and get it to the usb?
There is fine
So it click on it run it?
Yep
Sure that will do it to the usb and not my computer only?
When the install window pops up you will be able to set where to install it to
Click yes, then you should get another window
next
yep, F should be the letter of the USB drive
C should be your main hard drive
yep
don't forget to add the folder name cygwin to the end
D:\Cygwin?
yep
oh without capital?
it shouldn't matter
next
oh, wait. pause we may not need to do this one second to let me check
Ok
in the meantime I'm suspending the equipment, just in case
Alright I think I figured out how to do it
Oh
How?
why!?!?!?
Sometimes it just doesn't feel like importing(?
But
Do I back on what I was doing and delete all that just now?
I have no idea how to fix this error
Maybe we could ask for help?
We have time until Wednesday maybe we should give it a rest and go back to the code for now since we have almost a week if not
... i think maybe ... I figured it out
Tho it's a shame we can't properly test it
Because last time we supposedly did but, it has to be on another computer definitively
it did the thing
Perfect
Oh I need to go to eat and not so late after go to class tho in the middle or maybe during it we could do it
I download this..?
Leave me the steps just in case (!
(? *
Hope to see you real soon
nah, we need to change a few config files
first, we edit rust_toolchain/.rustup/settings.toml to be
default_host_triple = "x86_64-pc-windows-gnu"
default_toolchain = "nightly-2022-06-13-x86_64-pc-windows-gnu"
profile = "minimal"
version = "12"
[overrides]
this will switch to the gnu toolchain which doesn't need the link.exe
So link.exe wasn't actually needed?
the default toolchain msvc uses link.exe, the gnu one uses it's own
then we run cargo check and it should just work
Though we will probably need to move around some of the files to get the toolchain to actually install
oh, we do need to change PATH in the rust_toolchain/setup_rust_arduino.sh to
export PATH="$dir_path/.cargo/bin:$dir_path/avr/bin:$dir_path/.rustup/toolchains/nightly-2022-06-13-x86_64-pc-windows-gnu/bin"
and delete rust_toolchain/.cargo/bin/cargo.exe
Ah...
I understood too little so we will have to go through this slowly-
My class it's like 7 minutes away but
What would be the first step?
I already deleted
That thing we were doing
There's not toml settings
What it didn't took a picture
There
Pendrive tool chain, rust up but the other isn't there
Oh..
Ik
It's settings just that it's a .toml but windows doesn't say it, right?
yeah
PS C:\Users\fuchi> cargo check
error: could not find Cargo.toml in C:\Users\fuchi or any parent directory
PS C:\Users\fuchi>
Cargo check failed
you need to run it inside of the shell setup_rust_arduino.sh makes
busybox.exe ash setup_rust_arduino.sh
If I stop talking at any moment the class just started in two hour maximum I'm back
Oh so I do that and run cargo check on the script you did?
yep
And that would be the last step or we so something later?
Idk why I already feel nostalgic about "rust_beginners" (?
Tho I still belong there ig
I hope to in the future be the one that helps newcomers there
That depends on if it works or not
Right
After the class I'll try it or in the middle of the break
Btw I was kinda thinking..
If I'm still doing that function on the lcd
I mean
The Arduino one needed it
To be more tidy
This one is as God damn tidy and encapsulated as it can get so, does it needed?
I would just add a new state and function to execute in that state
Tho
I we still in that function have to print stuff with the lcd manually, but isn't it that much of a problem really?
And also a function that just calls another and anything else seems useless
Idk
Class is over
I'm doing the thing now
Taking it's time.
Oh yes
Errors
Ofc
Maybe just maybe
It's because I didn't do this
Because I didn't understand
Let me see if I understand
Delete this?
And then
yeah delete that
open vscode, go to file -> open, browse to the usb drive then rust_toolchain then open the setup_rust_arduino.sh file
I delete all that and copy this?
Oh or I change only
export PATH="$dir_path/.cargo/bin:$dir_path/avr/bin"
To that
Like that?
now open a new instance of setup_rust_arduino.sh (either exit and then rerun the command, or run it in a new powershell)
open a new powershell in the rust_toolchain folder. then run busybox.exe ash setup_rust_arduino.sh then cd ../[project]
then cargo --version --verbose
yes
okay now do a cargo check
Taking it's time
In the meantime
In class
I got REALLY
Frustrated
We finally use vs code
I created a folder in documentos next thw the rust one
Open it and create files to do the exercises and so
But constantly got errors of no such file or directory
I don't even know
How I got the first to work
Python aprobados.py
But the other exercise
That was in a new folder and I needed to create a module an import it
To another file and use it
I had this error again
I just can't fix it the code works if I use the button run it works
But I shouldn't have too
Also if I do a little part specification it works
And I really want to fix that so I can keep track of the class and actually I have an exercise to do
I will show you the screen shot of say the layout
The error
And what's the minimum I need to write in order for it to work
And thanks to that frustration I didn't pay full attention to the class -
It's just when I get left behind I didn't understand something prior or I couldn't do it because my pc is slow as fuck or stuff
I get really hugely frustrated and I close myself to keep on
Because I have like this idk
Perfectionism or idk the need to do things in order so if I didn't do something before I won't do the thing is after it infuriates me a whole lot
And when I'm like that every little things just gets me even worse like my slow computer that didn't help to try and fix the issue
the scene crime
PS C:\Users\fuchi\OneDrive\Documentos\codigos_python> py primer_modulo.py
C:\Users\fuchi\AppData\Local\Programs\Python\Python310\python.exe: can’t open file ‘C:\\Users\\fuchi\\OneDrive\\Documentos\\codigos_python\\primer_modulo.py’: [Errno 2] No such file or directory
the clue (error)
The annoying unsatisfying solution
python Primer_modulo\primer_modulo.py
To see if you know what was going on
Ignoring why the other one before this one didn't work because since I fixed with dark magic there's nothing else I can do about it
Ah btw going back to the other stuff
you aren't' in the right directory
So looks like it works
How do I fix it?
cd Primer_modulo
Ok
Now I did that but
It fails anyways
Let me try to
Copy paste it here
..
Dark magic
It worked
Well..
Well that's it
I remove the usb now?
On the bright side of things I finally got my gentoo working again
It only took like a week?
That's really good
.
which function was this? the one that let you print and align stuff?
I think it would be nice and maybe slightly useful but maybe so unnecessary idk, the context on why, when and where I did that function and where I'm standing it's waaaaay different
It printed, told me if it was too long, could automatically center stuff or I could chose where it would start and also with the empty const and all I avoided some annoyences when calling it
yeah, I think you should move to more functionality at this point with like the key pad
struct PrintOptions {
String toPrint;
int pos;
};
const PrintOptions empty = {"", 0};
void imprimirFila(byte posY, byte posX, String fila){
if(fila != ""){
byte caracteres_restantes = 20 - fila.length();
if(caracteres_restantes<0){
lcd.print("muy largo 1");
}
byte posicionX = posX == 'c'? (caracteres_restantes/2) : posX;
lcd.setCursor(posicionX,posY);
lcd.print(fila);
}
}
void imprimir(PrintOptions fila1 = empty, PrintOptions fila2 = empty, PrintOptions fila3 = empty, PrintOptions fila4 = empty) {
imprimirFila(0, fila1.pos, fila1.toPrint);
imprimirFila(1, fila2.pos, fila2.toPrint);
imprimirFila(2, fila3.pos, fila3.toPrint);
imprimirFila(3, fila4.pos, fila4.toPrint);
}
Ejemplos:
do{
imprimir(
{ "Elija una bebida", 'c' },
{ "1-Fernet con Coca", 0 },
{ "2-Sex on the beach", 0 },
{ "3-Agua", 0 }
);
do{
imprimir(
{ "Elija una bebida", 'c' },
{ "1-Fernet con Coca", 0 },
{ "2-Sex on the beach", 0 },
{ "3-Agua", 0 }
);
imprimir(
empty,
{ "preparando...", 'c'}
);
you can come back if you find you need it
This one
Well then if we aren't doing it there's one last thing I want from this project
It's to fully understand it and the only part I don't is the lcd module
Sorry
I2C module
Can you paste each section you want to discuss?
//! Doc for module
use embedded_hal::blocking::i2c::Write;
use lcd::{Delay, Hardware};
const ADDRESS: u8 = 0x27;
///Este Struct representa las conexiones del LCD
pub struct LcdConnection {
dev: arduino_hal::I2c,
data: u8,
}
impl LcdConnection {
///Crea una nueva instancia del Struct LcdConnection
///reciviendo el Struct como parametro y seteando mediante datos del datasheet
///que la backlight se prenda
pub fn new(dev: arduino_hal::I2c) -> Self {
Self {
dev,
data: 0b0000_1000, // backlight prendida por default
}
}
///Funcion que setea los bits del
///circuito I2C para controlar los
/// cables del LCD
fn set_bit(&mut self, offset: u8, bit: bool) {
if bit {
self.data |= 1 << offset;
} else {
self.data &= !(1 << offset);
}
}
}
impl Hardware for LcdConnection {
fn rs(&mut self, bit: bool) {
self.set_bit(0, bit);
}
fn enable(&mut self, bit: bool) {
self.set_bit(2, bit);
}
fn data(&mut self, bits: u8) {
assert!(bits & 0xF0 == 0, "Modo de 4-bits requerido");
self.data = (self.data & 0x0F) | (bits << 4);
}
fn apply(&mut self) {
self.dev.write(ADDRESS, &[self.data]).unwrap();
}
}
impl Delay for LcdConnection {
fn delay_us(&mut self, delay_usec: u32) {
arduino_hal::delay_us(delay_usec);
}
}
I brought it all just in case
that works
Let's see..
Well first some needes use statements I ain't questioning because in any case compiler will tell me add this use statement so
Needed*
The const address we declared it because we needed and adress to write to in the write function and I knew which one was it
Now, a public structure called lcd connection that represents lcd connections, what is dev and what is data?
dev is the i2c device to use for the communication
and data is the current state of the data to send
Remember me what was exactly the device? I remember I had struggle to understand it before
the data is of the form
Data3 Data2 Data1 Data0 BackLight Enable Unused Reset
7 6 5 4 3 2 1 0
Oh so the lcd connections indeed, the 8 wires it would normally have, data
And the i2c device I connected it to?
The arduino_hal:I2c is the i2c device inside the mega
It knows how to talk i2c
It will talk i2c to the address you tell it reading/writing data to the remote device
The circuit board on the back of the lcd takes these bits (on/off) and directly sets the wires going to the lcd board
So then in the new function I set the data so the back light it's always turn on, and in dev I send the i2c instance which had as information the speed of communication, the two pins that were used for the I2c protocol one input for receiving the data and one output to display and TWI which I don't remember what is, what was it!
? *
TWI is Two Wire Interface, or i2c. It's the name of the device on the Mega chip
Oh ok
Then there's this function
Set bit
Here I do have no clue
What's offset
What would be bit and why is it a boolean
What are the idea else conditions
if else*
The only thing that makes sense to me is the mutable reference to self as parameter
?eval ```rust
#[derive(Debug)]
struct Demo {
data: u8
}
impl Demo {
fn set_bit(&mut self, offset: u8, bit: bool) {
if bit {
self.data |= 1 << offset;
} else {
self.data &= !(1 << offset);
}
}
}
let mut x = Demo { data: 0 };
x.set_bit(3, true);
dbg!(&x);
println!("{:08b}", x.data);
[src/main.rs:19] &x = Demo {
data: 8,
}
00001000
()
It starts counting in 0?
offset is the bit to change, bit is the value to set it to (true=1, false=0)
yep
its the same indexes as these
The first one is
data = 0000_0000 | (2^offset)
which is
data = 0000_0000 | 0000_0100
|= is the assignment or operator and << is the shift left
<< also is times by 2 for each time you do it
So..
Self.data
Is by default 0000_0000
|= makes an or operation
And offset? I didn't understand the explanation earlier
x << y is "the bits of x shifted left by y number of bits"
I guess the or is to force a one with offset and and so it's a 0 and what is asking is if bit is true or false tho idk when would be in each state
yeah the or will make sure the one bit we selected is set without changing anything else
yep
And why is there a need to do the 1 <<?
because we need the value where a bit is set at the offset position
for example offset 3 is 0000_0011 in binary
which is not what we want
so we do 2 * 2 * 2 = 8 = 0000_1000
Mmm..
my math got away from me there
I don't get at all why 1 << makes power of two whatever the number of offset is
Because wouldn't it read like
The bits of 1 (it's just a 1) shifted left by offset number of bits
Mmm..
Oh
I think I get it
so
It would be like
I have 00000001
?eval mode=release ```rust
println!("{:08b}", 0b0110_1001_u8);
println!("{:08b}", 0b0110_1001_u8 << 3);
println!("{:08b}", 0b0110_1001_u8 * 2 * 2 * 2);
01101001
01001000
01001000
()
And the offset will move it base on what offeset is
So if offset 3
That 1
Will move to the left 3 spaces
Is that?
yep
which in binary each shift is a times by 2
why do we have to do an or operation to the the self.data, so self.data stores that at the end?
as seen here ^ (the times by 2)
if we didn't we would loose the state of all the other bits
So it's to not overwrite?
By doing an or all that was 0 and changed to 1
Would be 1
But what was 1 would stay
Now, could you explain to me what we do in the else case?
Why is there a not in 1 << offset
?eval mode=release ```rust
println!("{:08b}", !(1u8 << 3));
11110111
()
we flip all the bits to the opposite then and with data
which is
x & 0 = 0
x & 1 = x
so we only set one bit to 0 and keep the rest as they were
I think to understand best first I need to know
When would bit be true and when false
So I know what I want to do in else so I can the understand how to
say for example you wanted to turn off the backlight
which is bit 3
how would you take self.data=0b1011_1010 and disable the backlight bit?
Mmm
Wait
Didn't you say bit 3
Oh
Nothing
Well I would need to set bit 3 to 0 and only bit 3
and you have the operations, +, -, *, /, >>, <<, |, &, ^, !
but no data[3] = 1 thats not allowed
Ah wait
Let me see..
So in the else case
Since you said
Bit 3
Offset would be 3
So the result of 1 << offset
Would be
00001000
But then
You invert it
11110111
And then to self data
Do an and
And since that's the only 0 bit
That bit would be set to 0
And the others would remain the same
Got it
exactly
And bit is true when I want to send an order to set a bit and false when I send an order to turn off a bit?
yep
Yep
Mm..
Let's go through the first two that seems easier
because both take a mutable reference to self and bit to call self.set_bit
Oh
I guess those are reset and enable
So you are passing as argument offset the bit they are and well bit
yep
Why have a function for rs and enable?
That's what the lcd crate will call when it needs to do those operations
And what's exactly reseted and enabled? It's a turn on turn off or what is it?
Reset, resets the lcd back to it's default state, and enable enable/disables it showing anything
Oh ok
Then a tricky one
Data
Mutable reference to self obvious
What would be bits? The eight controllable bits of the lcd?
Its 4 bits of data
stored in the lower half of the byte
What does those 4 bits do?
the lcd crate uses them to talk to the lcd controller (the chip that actually controls the display pixels)
fn data(&mut self, bits: u8) {
assert!(bits & 0xF0 == 0, "Modo de 4-bits requerido");
self.data = (self.data & 0x0F) | (bits << 4);
}
They are a part of the 8 bits that control the lcd or
Another set of bits
so here bits is of the form
0 0 0 0 data3 data2 data1 data0
https://en.wikipedia.org/wiki/Hitachi_HD44780_LCD_controller is the way the 4 bits are used if you are curios
So I guess he uses assert because he wants you panic if its not using four bits but less or more idk
yep, the lcd crate can also do 8 wire mode
Idk how an and operantion would be equal to string, thanks even weirder
bits & 0xF0 == 0 is true if the 4 high bits are 0s
And how is true equal to 4 bit mode required (?
The ones we pass in?
?eval ```rust
dbg!(0b1000_0000_u8 & 0xF0 == 0);
dbg!(0b0010_0100_u8 & 0xF0 == 0);
dbg!(0b0000_0100_u8 & 0xF0 == 0);
dbg!(0b0000_0101_u8 & 0xF0 == 0);
[src/main.rs:2] 0b1000_0000_u8 & 0xF0 == 0 = false
[src/main.rs:3] 0b0010_0100_u8 & 0xF0 == 0 = false
[src/main.rs:4] 0b0000_0100_u8 & 0xF0 == 0 = true
[src/main.rs:5] 0b0000_0101_u8 & 0xF0 == 0 = true
()
yep
.
Ah wait
This isn't asserteq
What did assert only?
?eval assert!(false, "hello from the error");
thread 'main' panicked at 'hello from the error', src/main.rs:2:1
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
yep
And what happens below?
so we have this data coming from the lcd crate
0 0 0 0 data3 data2 data1 data0
but we need to send it like this
Data3 Data2 Data1 Data0 BackLight Enable Unused Reset
7 6 5 4 3 2 1 0
so we need to get the 4 bits of data into self.data but shifted over 4 spaces
self.data & 0x0F what would be for? Make sure the other bits, backlight and so are 0?
Because self.data
Is already 00000000
Or is it making sure in case something had been turned on before doing this idk
x & 0x0F is x & 0000_1111 which forces the 4 high bits to be 0
The high bits being the ones we don't control?
because there may have been data previously in self.data from the lcd crate
they are the once where we want to put the data the lcd crate gave us
So first we make sure data.self is 000000
0000_abcd where the state of a, b, c, d is unknown
And then we move the bits to the left to have it as we want them ig
And why the or?
Because anyways
It's 0000000
The or merges the two values together
0000_abcd | xyzw_0000 = xyzw_abcd
The self.data guaranteed to be 0 and the bits moved even if they are all 0 something significant happen ig
So now the bits we sent are in another position and self.data whatever it was it's now 0000000
okay here I will give an example
So we have self.data = 0101_1001 where the backlight is on the display is enabled and we have some data from the last time the lcd crate talked with the controller
the lcd crate now wants to send the data 0000_1101 to the lcd how do we do that?
1101 are the bits we send as arguments?
The position I mean
Because when we sent them they have to be 0000
lets assume we have been running the code for a while
But doesn't the function panic if we don't send 0000?
we did send it 0000 : 0000_1101

But
Below
We move then to the left
But they are already
All the way to the left
0000_1101 << 4 = 1101_0000
Btw this data bits are the ones that actually print stuff?
yeah
And why we need to move them and have it that way?
because we need to send this type of data over the i2c
So the data the lcd normally sends and the one that the I2C expects it's different so we need to say "translate" The message from the lcd way to the i2c way and that's what this function does by switching the high and low bits?
yep
Ok you can finish your example now that I Know this
you are suppose to finish it 

Well let's see..
Self.data is 0101_1001 and the bits I send are 0000, I want 0000_1101
It passes the assert statement
So first
Self.data goes from 0101_1001 to 0 because of the and 0x0F the 1001 changes the 0000 and the 0101 changes to 0 because I set those bits in the function
Then I have bits which is 0000 because it has two
And it goes to the left 4 spaces
Tho I will see before doing this 00000000 and after 00000000
It's now in the idiomatic way of the i2c
Thing is..
I never see it
What we want to end up with is: 1101_1001
Being other than 0
Because we said the and makes sure self.data is 0
And bits has to be 0
So this always end up in 0
makes sure part of it is 0
But
The other bits
Mmm
Mmm....
So
Basically
With write or whatever
I write
1001_000
0000*
But for the i2c what I want is
0000_1001
And this moves them
Ok I got it
no we already have the 1001 part where it should be
What.. -
Okay let me say it again
I was making another quick example-
Where the lcd wrote 1001_0000 so for the i2c I want 0000_1001 and call this function for that (?
no
that would fail the assert
God damn it's so complicated..
But If those are the bits to actually write
Why would they always be 0
Mmm oh
Mmm..
the bits variable is 0000_abcd because that is what the lcd crate gives us
We just pass that in to move the lcd message but they are not linked to the actual value of those bits in the byte?
the lcd crate gives them to us in the low four bits
0 0 0 0 _ a b c d
7 6 5 4 3 2 1 0
In this format the 7,6,5,4 the usual
Without the i2c we happily write to it
But since the creator of i2c hates humanity
The i2c doesn't directly understand what the lcd gives him raw
And the delicate one will only understand it in a backwards order so instead for 7,6,5 and so he wants 0,1,2,3
Up until that point is good?
not backwards, shifted over
a b c d _ bl rs 0 en
Could you do the comparison above what the lcd naturally does and below what i2c expects?
0 0 0 0 _ a b c d --- lcd crate
a b c d _ bl rs 0 en --- i2c
why above there isn't bl rs and that?
because those are set by the other methods in Hardware
Oh ok
The bits we pass to represent abcd ?
To the function we pass bits
4 onky
Only*
Either they represent something
the lcd crate passes them to us
Or nothing but they are merely used
So those bits would be the ones that are 0000 so the program makes sure they are the correct bits? (Tho idk why wouldn't they)
no they aren't 0000
Tho it's weird they are always 0 like it isn't ever enable or with backlight on
they are the a,b,c,d bits
But if we don't pass in 0000 the program panics
oh, yeah lcd will never pass in data to those
so abdc will have nothing in them?
wait, what have you been interpreting "_" as in those things above?
I think I am just unable to understand this and I better should give it up
Because it's nice to know and allow but if it literally it's just for the sake of it to understand it and I waste a lot of time I better stop
I'll just leave that that function changes the lcd format to something the i2c knows how to read
I have failed you 
No no, I'm just dumb(?
Idk why I couldn't understand it maybe I'm too asleep but I don't think is that, it's just weird maybe we would need a black board and a lot of patience
yeah 
I guess apply finally does the writting accesing to dev which is the I2C the adress to write to(adress of what?) And the data that got from the function data that the i2c can't act upon and it can fail so unwrap
More or less that ig
And well delay it's just so it know how to delay
It heavily calls my attention how lcd crate is calling all this created by us but it's too deep
So we now officially finished the lcd
Sadly it's too late to do more
But let's speak a slight bit of the matricial keyboard
okay
As I showed you
The code I made for it working alone with the library is the following
#include <Keypad.h>
const byte FILAS = 4;
const byte COLUMNAS = 4;
const char keys[FILAS][COLUMNAS] = {
{ '1', '2', '3', 'A' },
{ '4', '5', '6', 'B' },
{ '7', '8', '9', 'C' },
{ '*', '0', '#', 'D' }
};
const byte pinColumnas[COLUMNAS] = {22, 23, 24, 25};
const byte pinFilas[FILAS] = {26, 27, 28, 29};
Keypad keypad(makeKeymap(keys), pinFilas, pinColumnas, FILAS, COLUMNAS);
void setup() {
Serial.begin(9600);
}
void loop() {
char key = keypad.getKey();
if (key != NO_KEY) {
Serial.println(key);
}
}
The setup it needs it's the number of columns and rows, the matrix with it's keys, what pins are used for rows and which for columns and then finally create and object from keypad class with all that data and the call to makeKeyMap to turn the matrix into string
After that
You just use it.
In the project
The only thing I did
Was call wait for key to block the program and return the key pressed
In our lcd programm
We would only need to
Get rid of read_char and replace it for the equivalent in the matricial keyboard
That's it
But ofc first we are first gonna do a small project to test it, if we can get what key was pressed, get it to block, see if there's a wait for key like function
And well then create another project when we merge the two tho as I said.
It should be like
Really fast
And then we could do the last step to finish the base functionality which is to toggle the pins where the relays lay an x amount of time depending on the intensity x pretty easy
One last thing I would like that this time we look together for the library I go to crates.io and you tell me how to look for it, how to know if it's good and so, so I learn that
A well that's the plan
If there was no kibr
Library*
I have a code to detect the key pressed without library
#include <stdio.h>
struct Key {
byte id;
char name[5];
};
const struct Key ONE = {0b10001000, "1"};
const struct Key TWO = {0b10000100, "2"};
const struct Key THREE = {0b10000010, "3"};
const struct Key KEY_A = {0b10000001, "A"};
const struct Key FOUR = {0b01001000, "4"};
const struct Key FIVE = {0b01000100, "5"};
const struct Key SIX = {0b01000010, "6"};
const struct Key KEY_B = {0b01000001, "B"};
const struct Key SEVEN = {0b00101000, "7"};
const struct Key EIGHT = {0b00100100, "8"};
const struct Key NINE = {0b00100010, "9"};
const struct Key KEY_C = {0b00100001, "C"};
const struct Key ASTRK = {0b00011000, "*"};
const struct Key ZERO = {0b00010100, "0"};
const struct Key HASH = {0b00010010, "#"};
const struct Key KEY_D = {0b00010001, "D"};
#define COLUMNAS 4
#define FILAS 4
const struct Key KEYPAD[FILAS][COLUMNAS] = {
{ ONE, TWO, THREE, KEY_A },
{ FOUR, FIVE, SIX, KEY_B },
{ SEVEN, EIGHT, NINE, KEY_C },
{ ASTRK, ZERO, HASH, KEY_D }
};
void setup() {
DDRA = 0x0F;
Serial.begin(9600);
}
void loop() {
PORTA = 0b00001000;
for (byte columna = 0; columna < COLUMNAS; columna++) {
for (byte fila = 0; fila < FILAS; fila++) {
if (PINA == KEYPAD[fila][columna].id) {
char imprimir[25];
sprintf(imprimir, "Se presionó la tecla %s", KEYPAD[fila][columna].name);
Serial.println(imprimir);
delay(200);
}
}
PORTA >>= 1;
}
}
This one
So well I think tomorrow we could actually do that I just said so in the weekend finally the real deal would begin
Rfid
Once we are done with the rfid it's basically done
Because sensors aren't that complicated
I'm a bit worried but interested on how is it gonna be(?
I please hope it ain't that hard and it doesn't take that long
we will see 
I will pray, that would be mean we wouldn't be that far way from finishing this
Oh and
In some days I'm getting my raspberry Pi pico
So after the project I would want to be like prepared for it
Install the abstraction for this one
Be able to use that Arduino ide
And install whatever I need for micro python
I would guess all my Arduino code would work so I don't have to re learn or anything
Micro python since I know python idk if I would need to know specifically that also idk if I'm really gonna use it instead of Arduino IDE or rust
Now..
I would like to program it with rust
But there's a set amount of times I'm re writing a project
And two times seems like somewhat of a waste of time
Even though I would really like for my project to instead of being in a Chinese Arduino board in c++ be in raspberry Pi in rust but
I really don't want to do all over again even tho I want to learn how to use rust in the raspberry pi pico
But there's nothing else I can do so I would kinda just have it there
That's the Shame with embedded systems I won't be able to learn because there's nothing I can program
But in any case just help me with the installation of the Hal and that's it
In the worst case scenario at least I already know Arduino and could learn micro python
Unless the same code we did works maybe with reaaaally slight changes in that case, microcontroller change
But idk, I hope
Because I don't want to learn 80 ways of doing the same like I'm always re learning
And that would make sooo easy the transition to raspberry Pi
I can already program it an Arduino ide like in Arduino board only that I have two extra possibilities of plain C++ and micro python if I get that much into python but I would like that I'm also able to program it in rust, because rust+raspberry Pi pico sound reaaaally powerful
Back home
@coral geyser are you present?
yep
Because in some minutes I'm turning the pc on
So..
How do I go to crates.io, just type it and it's the first?
yep
How intuitive is it to navigate in?
I had close to zero experiences searching for libraries
Ok I'm in
Do I search it as keyboard? Keypad?
yep
Which of the two-
try both
Ok let's see
Mmm
Idk what would be platform agnostic
The second one says embedded hal and had been updated at least 1 year and not 4
The ones below seems like nothing to do
"A crate for reading a 3X4 keypad with embedded-hal"
Mine's 4x4 tho
Wait let me check
Yes 4x4
and keypad is 4 years old
which means it probably wont work nicely with your new embedded-hal
It seems that keypad was the correct word
Why not have dependencies for something as normal as a matricial keyboard
They barely had for an lcd, the ecosystem for embedded rn is really small it seems
Apparently, no one has needed it/wants to take the time to maintain a public one
What do we do? Program it without library?
looks like it
Only two libraries one even tho updated 1 year ago(which is still quite some time) but for a another keyboard and also way less downloads than the other that's really old
What a bad Possition-
It's a shame that rust a low level system programming has such an small embedded ecosystem when compared to the web development one for example
So I go out of crates.io and create the new project?
We need more people
maybe I will roll it into sketchbook
and the lcd stuff to
A library for a matricial 4x4 keyboard?
My sketchbook crate is designed to mimic arduino programming
You plan to do a library with all you learnt?
You can ask me the code we made if you don't have it when you need it
hmm I actually just finished redoing some of the traits in it. Maybe I should try it out on the arduino now
I created serial too because
We will need it at the very least to print to the terminal what key we got
First we should be able to tell the key that was pressed and after that make it a blocking function just like the Arduino's version waitForKey
Since we are using no library we can base in this code I have already sent where I detect the key pressed, do in a more beautiful rusty way ofc
I don't remember that well how it worked but you know C and Arduino so I don't have to explain (?
#include <stdio.h>
struct Key {
byte id;
char name[5];
};
const struct Key ONE = {0b10001000, "1"};
const struct Key TWO = {0b10000100, "2"};
const struct Key THREE = {0b10000010, "3"};
const struct Key KEY_A = {0b10000001, "A"};
const struct Key FOUR = {0b01001000, "4"};
const struct Key FIVE = {0b01000100, "5"};
const struct Key SIX = {0b01000010, "6"};
const struct Key KEY_B = {0b01000001, "B"};
const struct Key SEVEN = {0b00101000, "7"};
const struct Key EIGHT = {0b00100100, "8"};
const struct Key NINE = {0b00100010, "9"};
const struct Key KEY_C = {0b00100001, "C"};
const struct Key ASTRK = {0b00011000, "*"};
const struct Key ZERO = {0b00010100, "0"};
const struct Key HASH = {0b00010010, "#"};
const struct Key KEY_D = {0b00010001, "D"};
#define COLUMNAS 4
#define FILAS 4
const struct Key KEYPAD[FILAS][COLUMNAS] = {
{ ONE, TWO, THREE, KEY_A },
{ FOUR, FIVE, SIX, KEY_B },
{ SEVEN, EIGHT, NINE, KEY_C },
{ ASTRK, ZERO, HASH, KEY_D }
};
void setup() {
DDRA = 0x0F;
Serial.begin(9600);
}
void loop() {
PORTA = 0b00001000;
for (byte columna = 0; columna < COLUMNAS; columna++) {
for (byte fila = 0; fila < FILAS; fila++) {
if (PINA == KEYPAD[fila][columna].id) {
char imprimir[25];
sprintf(imprimir, "Se presionó la tecla %s", KEYPAD[fila][columna].name);
Serial.println(imprimir);
delay(200);
}
}
PORTA >>= 1;
}
}
But let me remember or try to explain how this worked
So I created a Struct Key that represents each key, one field is for say the ASCII name the character and the other for the combination of binary needed to be that number and create const instances of that struct to have all the possible keys instanciated
And I make a define for columns and rows, instead of just using 4, 2 two times, for reading purposes and that also makes the code more flexible to change here the number of columns and rows in each time I use it
In the setup I set the portA of the MEGA so I have the least significant bits as outputs and the rest as inputs
Because rows were inputs and columns outputs, i don't remember if it's that way of backwards tho but you get the idea of what I'm doing
And I'm also initializing the serial communication
Now here is where it gets tricky to remember...
I remember the base logic of
Moving the 1 in each column and see if it matches another 1
Because rows would be all 0 until someone presses it and made a 1
But columns I say what they are
And what's convenient is to move a 1 a column at a time
And then I know which key it is, surely you know how a matricial keyboard works anyways, but it's to say yeah that for loops are doing that, now let me see if I remember how..
Ah yes I kinda forgot to mention I also did a matrix for the matricial keyboard
Oh ok
I think of remember now, more or less
So first I initialize PORTA to 00001000
That one and the right 0 to that are the columns I control and move the bit around to ask
My inputs
As a programmer ofc
The output is the guy pressing down the button
So first I initiate a for loop for each column means it will run four times asking in each one of them, and then at the end of that for loop I move the 1 to the other column to keep asking what's inside
Now going one level deeper into the for loop
I have a for loop that will ask for each of the rows in the current column
And inside that for loop is where the comparing occurs
I ask if the current bits of the PORTA match with the id (bit combination needed and see that thanks to the for loops I ask in an specific could and row, to ask for an specific combination until it matches) in the keypad matrix which is of the type key, if it does I declare a char array to print it to the screen , and call sprintf to copy that string to imprimir and the I print it to serial monitor and add a delay, if it doesn't match I ask for the next row until I run out of them and ask for the next column and it's set of rows
Phew
Took me a little bit but I remember how it worked
How is it, could you understand my old code?
yep
Well should we replicate that or you know of a better way to do it?
I mean surely in rust there's a better way than in C fashion
We could do the same thing were we directly write to the registers, but I would recommend we do it manually with each pin
To the registers?
PORTA, ...
I mean I just sayed hey key one this is your bit combination and then you know moved in the matrix with the column and rows variables and the for loop then asked if the PORTA matched that then the other
Oh
Why? Isn't it more comfortable that way? Because if not we would have to make 8 questions but for each possible key
Like if this pin is 0 and this one is 1 and that one is also 1 and the other is also 0 ..
And so
We loose the type safety rust provides
Doesn't embedded hal has a safe way of doing that , is that operation by definition unsafe? Why?
And it's worth being a lot more verbose?
The operation is unsafe because it changes the state of the pins and the mode of the pins
Btw sorry I'm going to shop I'm back in 5 minutes it's close
This question could go either way. We can do either
No because there's one for the state of the pins and another for the bit in the pins, in setup I change only once the state because it doesn't need to be changed again and the I just once write the starting combination, move only that bit and ask for the whole port instead of every bit in all 8 pins seems so much verbose and unnecessary work tho idk how it would be
DDRA sets inputs and outputs and PINA is for read/write
yeah, it's unsafe from a type perspective
because you bypass the types which is fine to do, if you do it right
You mean I can write a 1 to an output which I shouldn't be able to set a 1 to?
I would guess is that
Also if a remember the avr register defaults correctly this can cause a short circuit if you press 2 buttons at once
I'm back
Well I didn't have to think about multi pressing at the time, but I read it was one of the features of the library
Tho what matters now is if we choose the register or individual pins way
The thing that concerns me when working with individual pins for things like that is that I know I'm writing +80 lines of could that could be sum up
It just seems like so much extra work, that makes me doubt
you get to choose 🤷♂️
individual pins: Rust's type system will help you but will be more verbose,
using PORTA, ... : probably shorter code, but you will have to interact with unsafe Rust
I mean having experience with unsafe rust would be interesting but maybe is too much for a begginer
What would you do? Isn't it kind of our objective to avoid verbose options?
I would use individual pins, unless there were other constraints. My default is always no unsafe unless necessary
Could we maybe build our own safe PORTA alternative and that? Like a struct or smth?
Should we?
I would just make a Keypad struct that handles the keypad
whenever, I am just working on sketchbook on the side
I mean, what would be the first step, create a Keypad module?
that would be a good first step
Done
Now what? Create the Keypad Display that will do all the work just like in the original library we had a Keypad class which from we would create a keypad object with crucial information in it's constructor?
do we need a Display struct in this version of the project?
Mmmm
Well let's see
The information that the library needed to function was
The number of columns and rows, which pins went for each, the matrix that was converted to a string with makeKeyMap..
Tho those were parameters in the constructor
In my Basically C code I had the bit combination and the ASCII character, the matrix and number of Columns and Rows were also needed
can we make the assumption that we will only be working with a 4x4 keypad for this project?
Ofc tho I needed them in my C code to iterate and because it was readable, the original library no clue
I mean I can just iterate four times but it is easier to say I'm iterating over the columns and each row of them
Which takes btw
Is there a define here?
Because it makes things so readable and sometimes comfortable to change a value in just one place and not all
We can do better
That means it doesn't exist(?
cols: [T; 4],
...
for col in cols {
// col is T
}
Not in the same way in rust they would be const COL_NUM: usize = 4;
Well so what would be the struct fields?
try adding these as fields see how far you get
What would be the type of a matrix?
Eh..
I didn't understand at all
Ik that a matrix is an array of array
So is an array with two [][]
And the two of them hold intergers for the index
At the type of an array at least in see is int* or char* an so
I don't understand at all this
?eval ```rust
let x: [[i32; 3]; 2] = [
[1, 2, 3],
[4, 5, 6],
];
dbg!(x);
[src/main.rs:7] x = [
[
1,
2,
3,
],
[
4,
5,
6,
],
]
()
[T; N] is an array
struct shouldn't be capital
Why ;?
?eval ```rust
Struct A;
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `A`
--> src/main.rs:2:8
|
2 | Struct A;
| ^ expected one of 8 possible tokens
?eval ```rust
struct A;
()
So we have [[]] as an array of arrays in the first array we need it's size [[]Y]
And in the second we also need it's size
Like any array
yep
its just how the syntax is
To separate elements in an array or what?
?eval ```rust
let x = [1, 2, 3];
let y = [0; 3];
let z: [i32; 3] = [1, 2, 3];
dbg!(x, y, z);
[src/main.rs:5] x = [
1,
2,
3,
]
[src/main.rs:5] y = [
0,
0,
0,
]
[src/main.rs:5] z = [
1,
2,
3,
]
()
[A; B] is read as "array of A with length B"
in type position A is a type
in expression position A is a value
Why the first array has generic type and Y doesn't have a generic type?
And also why a generic type if we know we are storing ASCII
In a nesting [[T; X]; Y] the outer array (of size Y) has a element type of [T; X]
It's for explanation, you should fill it in with whatever you need
We leave it as T or know that I know I type char there?
what do you want?
you get to pick
Well a char because it can't be anyother value
so this would be th struct
struct Keypad {
columns: u8,
rows: u8,
pins: u8,
matrix: [[char; X]; Y]
}
Is it fine that way?
should X and Y be actual values also?
Well we know this a 4x4 matrix
The size is know and won't change
this is a*
So maybe we could instead of X and Y just do 4
Or do the define like syntax to make it more readable
I guess X and Y would be fields if I needed to know what kind of matricial keyboard is
Like the other library that takes it as parameters
try out what you think is best for the moment
Mmmm
It would be like lying to pass as parameters X and Y
Because I would be saying
Hey pass as parameters which keyboard is it
When it will only accept one answer
So to avoid mistakes or just being tidy
If it can only be one thing then why ask what it is
So we should set it to be only a 4x4 to work for this project as you suggested
If we are in the mood later and make it generic that would be cool
Anyways I'm having dinner, coming back soom
Soon*
I'm back
So
Should the signature change to?
struct Keypad {
columns: u8,
rows: u8,
pins: u8,
matrix: [[char; 4]; 4]
}
Looks abt right to this occasional observer
Thanks for the appreciation
Mmm well having the structure..
Wait now that I think about it..
What would columns and rows store?
The number of them? Which I said why that wouldn't make sense
Or the pins associated with them
Then in that case
Pins is not necessary
But rather a bit combination maybe
Like in my c code
I could also have a separate struct for a key that could be inside this Keypad struct also that could manage that..
Ok I will leave it here so I don't forget
Since rows and columns are default information
The fields should be what pins are the ones for rows and columns so, maybe change the name?
Also get rid of pins field
And create the same struct key that contains the name meaning the ASCII character, and the id being the bit combination needed, and the key struct would also be inside the keypad struct or something similar
Where are we putting the pins that the Keypad struct will control?
In the columns and row fields because it's important to know, because the columns we have to move the bit with 1 and in rows we needed to check if it was pressed
But maybe change the name to column_pins
row_pins
I mean where are we storing the things that lets us change the pin's state
