#Arduino Help

1 messages · Page 3 of 1

coral geyser
#

hmm, so the second line works

wary cloak
#

Ah

#

If I recall

coral geyser
#

It just decides to jump 2, weird

wary cloak
#

When you go out of scope in characters

#

It does weird things

#

So just

#

Live with that limitation

#

If you need to write

#

A long sentence

coral geyser
#

yep, thats what your struct will fix ferrisGlasses

wary cloak
#

Just divide it in two lines with two calls to write

coral geyser
#

alright so it works

#

I just wanted to make sure that the second and forth line were working

wary cloak
#

Ok so I guess we can do the first part which is like my original code, just make it work write the text we need and so all manual, and when it works then make a function and stuff to make it like the last version

#

I just realized something..

coral geyser
wary cloak
#

That could be problematic

#

Well idk if it will

#

But we kinda need to use the serial port

coral geyser
wary cloak
#

To emulate using the keyboard

#

Because if not

#

We kinda

#

Can't test it

#

We can do something simple

coral geyser
#

alright

wary cloak
#

I mean

#

Why I first learnt

#

How to use the LCD

coral geyser
#

back to the docs!

wary cloak
#

I only cared that it stayed until I sensed something

#

I didn't care what

#

Tho..

#

Back then

coral geyser
#

okay do you know how the Arduino connects to the computer to send text? ferrisHmm

wary cloak
#

I only did that because I thought the LCD wouldn't care for what I pressed which I quickly realized it wasn't the case

wary cloak
#

But here

coral geyser
wary cloak
#

I could show you the code for the LCD very first shitty version

#

Which used the serial port only to wait for something to be send

#

Read it, do nothing and wait again

#

Let me see..

coral geyser
wary cloak
#

Ok this shit doesn't let me copy the text

#

But there you can see it

#

It basically was

#

Serial.available that will only enter when there was something to read, but then I couldn't use it again without reading to it because next time I used serial.available there sould be something

#

Tho I think I made a better version of it if I remember

#

I made a function waitForInput

#

But it's not there

#

Tho idk if showing this will help because I have no clue how are we using the serial port here

#

It can be use in vs code because you can kinda have the arduino IDE here

#

But

#

That would be arduino IDE and we don't program there

#

There's ofc another solution

#

And it's to keep working on the LCD without it

#

And just comment a previous text that worked and see if we can write another

#

Then leave it where we can and when we do keyboard

coral geyser
wary cloak
#

Properly test it

#

But I think using the serial port it's inevitable

#

Because of..

#

The RFID

#

It's impossible to test otherwise so..

coral geyser
wary cloak
#

How do we do that?

#

Oh btw I forgot to mention but I have kinda good news

#

The keyboard

#

I had done if I recall

coral geyser
#

cargo doc --open

wary cloak
#

A code in arduino without a library that could detect the key I pressed so

#

It's likely going to be way more simple even if there wasn't a library for it, but if there is, piece of bread

wary cloak
coral geyser
wary cloak
#

We were here

coral geyser
# wary cloak

scroll to the top, click the header to go back to the root of the docs

#

arduino_hal is the one we want to start with

wary cloak
#

So, usart

coral geyser
wary cloak
coral geyser
wary cloak
coral geyser
#

We want to follow the example

#

but it looks to be slightly out of date

wary cloak
#
let dp = arduino_uno::Peripherals::take().unwrap();
let mut pins = arduino_uno::Pins::new(dp.PORTB, dp.PORTC, dp.PORTD);
let mut serial = arduino_uno::Serial::new(
    dp.USART0,
    pins.d0,
    pins.d1.into_output(&mut pins.ddr),
    57600.into_baudrate(),
);

ufmt::uwriteln!(&mut serial, "Hello from Arduino!\r").void_unwrap();

loop {
    let b = nb::block!(serial.read()).void_unwrap();
    ufmt::uwriteln!(&mut serial, "Got {}!\r", b).void_unwrap();
}
coral geyser
#

arduino_uno::Serial::new -> arduino_hal::Usart::new

coral geyser
wary cloak
#

So what do I do now?

#

Ah here are the functions that may be useful

coral geyser
# wary cloak So what do I do now?

add ```rust
let mut serial = arduino_hal::Usart::new(
dp.USART0,
pins.d0,
pins.d1.into_output(&mut pins.ddr),
57600.into_baudrate(),
);

coral geyser
wary cloak
#

Maybe just maybe write_byte would do

#

Or in any case

#

Read and write

#

So we could see what we send and respond

coral geyser
wary cloak
#

Oh then just read

coral geyser
wary cloak
#

And we store that data we read and maybe match it or use and if block

coral geyser
#

The example is a little old and the API changed

wary cloak
#

Error it's the same tho

#

Oh

#

I get it

coral geyser
# wary cloak

And the baudrate you can do as arduino_hal::usart::Baudrate::new(57600)

#

or mark it as a u32 with 57600u32.into_baudrate()

wary cloak
#

Ok no errors

wary cloak
#

So what now?

coral geyser
#

now add a ufmt::uwriteln!(&mut serial, "Hello from Arduino!\r").void_unwrap();

wary cloak
#

Below serial?

coral geyser
#

yep

wary cloak
#
Checking rust_lcd v0.1.0 (C:\Users\fuchi\OneDrive\Documentos\Codigos_Rust\rust_lcd)
error[E0599]: no method named `void_unwrap` found for enum `Result` in the current scope
  --> src\main.rs:22:59
   |
22 |     ufmt::uwriteln!(&mut serial, "Hello from Arduino!\r").void_unwrap();
   |                                                           ^^^^^^^^^^^
   |
  ::: C:\Users\fuchi\.cargo\registry\src\github.com-1ecc6299db9ec823\void-1.0.2\src\lib.rs:87:8
   |
87 |     fn void_unwrap(self) -> T;
   |        ----------- the method is available for `Result<(), void::Void>` here
   |
   = help: items from traits can only be used if the trait is in scope
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
   |
3  | use arduino_hal::prelude::*; // trait ResultVoidExt
   |
help: there is an associated function with a similar name
   |
22 |     ufmt::uwriteln!(&mut serial, "Hello from Arduino!\r").unwrap();
   |                                                           ~~~~~~

For more information about this error, try `rustc --explain E0599`.
error: could not compile `rust_lcd` due to previous error
coral geyser
#

as the help says ferrisHmm

wary cloak
#

In all rust projects I always see 9000 use statements

coral geyser
#

basically each use is an external thing this code needs

wary cloak
#

I mean it executed but..

#

Since there's also the LCD stuff let me see if it got lost in the terminal

#

No, nothing happened

coral geyser
wary cloak
#

Maybe because we didn't read what we write?

wary cloak
#
Compiling rust_lcd v0.1.0 (C:\Users\fuchi\OneDrive\Documentos\Codigos_Rust\rust_lcd)
    Finished dev [optimized + debuginfo] target(s) in 4.26s
     Running `ravedude mega2560 -b 57600 target\avr-atmega2560\debug\rust_lcd.elf --port COM6`
       Board Arduino Mega 2560
 Programming target\avr-atmega2560\debug\rust_lcd.elf => COM6

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.03s

avrdude: Device signature = 0x1e9801 (probably m2560)
avrdude: reading input file "target\avr-atmega2560\debug\rust_lcd.elf"
avrdude: writing flash (5994 bytes):

Writing | ################################################## | 100% 1.28s

avrdude: 5994 bytes of flash written
avrdude: verifying flash memory against target\avr-atmega2560\debug\rust_lcd.elf:
avrdude: load data flash data from input file target\avr-atmega2560\debug\rust_lcd.elf:
avrdude: input file target\avr-atmega2560\debug\rust_lcd.elf contains 5994 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 1.15s

avrdude: verifying ...
avrdude: 5994 bytes of flash verified

avrdude: safemode: Fuses OK (E:FF, H:D8, L:FF)

avrdude done.  Thank you.

  Programmed target\avr-atmega2560\debug\rust_lcd.elf
PS C:\Users\fuchi\OneDrive\Documentos\Codigos_Rust\rust_lcd>
#

This is the output

coral geyser
coral geyser
wary cloak
#

Ah right

coral geyser
#

But you can just do cargo run -- --port COM6 -c to add it back

wary cloak
#

Ok now yes

#

Tho what we need is to read our input like the keyboard and depending on that what the LCD will show next

coral geyser
# wary cloak
nb::block!(serial.read()).void_unwrap()

will wait for one Enter key

wary cloak
#

Let's see, let's put that above the write

#

If that returns the one entered key as an ASCIJ

#

It's perfect

coral geyser
wary cloak
#

Because if you say

#

Saw*

#

In my code both versions

#

I merely use

#

WaitforKey

#

Which does just thatb

#

Stops everything waiting for a key

#

And gives it back

#

And then I ask in an if which key it was

#

So we have what we need

#

Btw new error

#

Tho just like write

#

I'll had to add another use

#

use embedded_hal::prelude::_embedded_hal_serial_Read;

coral geyser
#

I do love that cargo just tells you what to do ferrisChefKiss

wary cloak
#

Ok I think it worked so

#

Finally

#

We have everything we need

coral geyser
#

yep, you should have everything to rebuild that first version

wary cloak
#

Next will be

#

To understand the basics on how to I mean

#

I will ask you about all that shit in the module later

#

For now

#

I just want to understand the how to use

#

Basically

coral geyser
wary cloak
#
let i2c = arduino_hal::I2c::new(
        dp.TWI,
        pins.d20.into_pull_up_input(),
        pins.d21.into_pull_up_input(),
        50000,
    );

    let lcd_conn = LcdConnection::new(i2c);

    let mut lcd = Display::new(lcd_conn);

    lcd.init(FunctionLine::Line2, FunctionDots::Dots5x8);
    lcd.display(
        DisplayMode::DisplayOn,
        DisplayCursor::CursorOff,
        DisplayBlink::BlinkOff);
    lcd.entry_mode(EntryModeDirection::EntryRight, EntryModeShift::NoShift);

    lcd.position(0, 1);

    write!(&mut lcd, "Hello, my number today is {: >4}", 42).unwrap();
#

That

#

And I think

#

We would end for today

#

It's gonna be 5 am

#

Tomorrow I'm absent from 15:00 to 18:00 Argentine hour tho

coral geyser
#
let i2c = arduino_hal::I2c::new(
    dp.TWI,
    pins.d20.into_pull_up_input(),
    pins.d21.into_pull_up_input(),
    50000,
);
wary cloak
#

I think there's like two hours less

#

Wait for me to put everything away

#

And then we'll talk about it

#

Ok I'm back

#

So first we create a variable called i2c, what does it stored and why doesn't it need to be mutable?

coral geyser
wary cloak
#

Store*

coral geyser
#

It will manage d20 and d21 to perform i2c communication

wary cloak
#

I2c device?

coral geyser
# wary cloak I2c device?

The mega has some special hardware internally that can connect to pins d20 and d21 that knows how to talk to i2c devices

wary cloak
#

i2c device is the micro component it talks to in this case the LCD?

coral geyser
#

the lcd i2c controller is the extra board attached to the back of the LCD

wary cloak
#

And which is the device, the controller?

coral geyser
wary cloak
#

Ok

#

So we create a variable called i2c that is equal to a new instance of an I2c device which takes as parameters to it's "constructor" The I2c port , the pins that communicate one with the other and the speed of communication

#

Right?

wary cloak
#

The speed is in bits per second? Is there are reason to pick that number?

coral geyser
wary cloak
#

Oh ok

coral geyser
wary cloak
#

And then we create a new instance of our struct LcdConnection that represented the Lcd connections wow and pass in as a parameter the device

coral geyser
wary cloak
#

I don't remember how was the struct inside let me scroll up but in the meantime

#

Why do we pass in the device as an argument?

coral geyser
wary cloak
#

Ok then next is the lcd variable

#

I see another structure come into play another layer

coral geyser
#

yep, this layer's job is to know what instructions to send when

wary cloak
#

So we have

#

The device

#

The lcd connections

#

And what would you call what it is?

coral geyser
wary cloak
coral geyser
wary cloak
#

And then finally having the mutable variable lcd that stores all that setup we can start calling methods obviously starting with init but, what the heck are init's argumenta

#

In arduino init just turns it on

#

But here it receives arguments

coral geyser
wary cloak
#

The first we saw was

#

For underlying or not the lines in which there's text

#

Weird

coral geyser
wary cloak
#

But what about the second one

#

Oh

#

Characters in dots?

#

Oh so you mean

#

Font size

coral geyser
#

Some LCD of this type has 5x8 dot characters some have 5x10 dots

wary cloak
#

And I ever not touch it

#

Better*

coral geyser
#

just like with the Line1 ferrisButGrimacing

wary cloak
#

Ok then there's display tho it's just setting enums like configuration to ask if you want to show a cursor and it's blinking this is going to be really useful for me, but what about display mode haven't we turned it on before?

coral geyser
#

Useful in some devices

wary cloak
#

So it's the way you would turn off the display

coral geyser
#

yep

wary cloak
#

And, what is entry_mode?

coral geyser
wary cloak
#

Wdym by if you just write into it?

coral geyser
#

I think EntryRight prints left to right

wary cloak
#

I think I get the entry mode direction I guess it's if it's starts writing from left to right or vice versa

#

Oh ok

#

Like normal

coral geyser
#

and shift likely does the wrapping

wary cloak
#

It's a lot more customizable

wary cloak
coral geyser
# wary cloak Wrapping?

It either makes it go to a new line (properly) or it scrolls the text to the left if you have to much

#

I am not exactly sure

wary cloak
#

Mmm we will have to test it tomorrow

#

It says no shift

#

We will leave like that for now

coral geyser
#

there is also a Scroll option you can set

wary cloak
#

Well I guess that would be all the setup so now we can actually write by saying position first , this is just like setCursor in arduino, where you start from rows and colums

wary cloak
coral geyser
wary cloak
#

Oh so for like a lot of text?

#

In a loop ig

#

It calls my attention there's no lcd print or write but it's rather a macro.

coral geyser
#

I am not sure, I haven't used a LCD like these. I have only used a different driver

coral geyser
wary cloak
#

So, it takes a mutable reference to the variable, and the other argument it's the text, and it could fail for whatever reason idk, so we call unwrap to deal with it's returning result type with panic if it's an error, right?

coral geyser
wary cloak
#

And my last question about the write macro

coral geyser
wary cloak
#

If that's ok, would be the weird syntax of {: >4}, 42 , inside the bracket goes the 42 but instead of just writting the 42 you write a weird thing inside brackets

coral geyser
robust mountainBOT
#
  42
()
coral geyser
#

It right aligns with 4 chars

wary cloak
#

I think that would be necessary with lcd.position tho

coral geyser
#

?eval println!("{:>20}", "hello");

robust mountainBOT
#
               hello
()
coral geyser
#

This would right align on your display (4x20)

wary cloak
#

Well now that I understand all the setup needed to be able to write to it, and how to write to it and set the position of start, as well as how to make the cursor appear or disappear, blink, stop blinking, I'm kissing one thing

#

If there's a clear method which should be to erase the previous text to write a new one

coral geyser
wary cloak
#

And with that I think I have the equivalents to all the instructions I used and know for the C++ equivalent

#

Well my plan is the following

#

Tomorrow my goals are two

coral geyser
robust mountainBOT
#
       hello        
()
coral geyser
wary cloak
#

First to do the first version of the code I mean it works it does what it needs to do, all manual like the first time I did it in arduino

#

And second

#

To understand everything we've done, which includes more or less understanding what's going on in the module

#

And then on Sunday make the final version of the LCD so I can finish it off one micro component less

#

I hope at least(?

#

At least the other two should be easier, keyboard it's reaaaally possible without a library if there's ever one it's basically all done

#

And the other things is just sending a one to a pin when a condition is met

#

Not even a need for a library or something fancy

#

So this is literally the worst it will get (?

#

(Until RFID)

#

Phew

#

Last question

#

Basically all that stuff with did with the module to handle I2C wA only so we could pass it as an argument to Display and now on we are only using the library which would be internally using our module?

wary cloak
#

And when we are going to do the last part say when we are gonna avoid doing the manual work on main like the final version, we are making another module?

#

Or a library crate?

wary cloak
#

When this is finally done it's gonna be proud worth it(?

#

Tho I'm afraid on how's working in the RFID gonna be

#

I'm begging to God there's not only an RFID library

coral geyser
wary cloak
#

But also that it includes how to deal with the SPI protocol

wary cloak
wary cloak
#

Is this one for our AVR-hal?

#

If so, god bless it

coral geyser
wary cloak
#

It is already hard with a library, without it, it's giving up worthy

#

I'm so excited to get there tho

#

And see how is it

#

And also that my rust version surpases my original C++ version

#

Which isn't hard because that version is stuck and idk what to do

#

That's one of the reasons I do this

#

But I would likely do it even if it was finished(?

#

Anyways good night, I think?

#

Once again thank you very much

#

I hope tomorrow's easier

coral geyser
wary cloak
#

Tho what can I say this is exciting anyways

wary cloak
#

Ok now I can work again

#

If I recall we can finally just start coding right?

#

Tho I forgot yesterday to ask you one thing about main, I asked you all about how to use the lcd and how the library worked an all but I didn't ask you about the serial port

#

And also..

#

That documentation we had yesterday that I thought it was merely of the LCD, is actually the Arduino-hal documentation we can consult for anything not component specific?

#

Or maybe even a component if lucky?

coral geyser
wary cloak
#

It has all the documentation I will need for the arduino-hal abstraction or peripheral specific is elsewhere? Since this even had the LCD and I2C

wary cloak
#

Well that's cool

#

Btw once I send my LCD function to one of my schoolmates to make he's life easier so I have the function alone with examples instead of having to show you the whole project code

#

I guess it should be easy to replicate in rust

#
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'}

    );

#

This does everything, center the text or allow you to do manually, print stuff or tell you that's too long if you over the character limit and if you need to write only the first too lines and omit the last too there a empty constant they are all set by default but I you have a text in the center you can use empty in the first line

#

It has everything built into it

#

There's a function to print to only one line because the original way was too repetitive and there merely another function that calls the first four times

#

And a struct to make things easier

#

And also the logic is there so I guess when we have to do it, I hope it isn't that much of a challenge to re write that

wary cloak
#

I guess we will make the print functions methods of the PrintOptions struct

#

Well any ways for now I have to make the original manual stuff

#

Tho because I'm used to it

#

I will likely make it in cpp fashion or something

#

So maybe you could then show me an idiomatic rust way maybe if needed re factor

#

I was going to do the exactly very same that in the original code , first set the position, then print the stuff I want, add the serial port stuff that waits for a character so it stays until you choose, then when you chose, if it's something I don't want,clear then print something like, incorrect value, clear again and return so we go back to the last menu, and when what I want is pressed I do the exact same

#

Just if and else asking for an specific ascii character

#

I thought maybe there was a functional way or doing it or that instead of an if else use a match or if let idk

#

An idiomatic way of rust to do it better or more rusty

#

Ofc if not necessary and verbose not but just to make sure I ain't taking advantage of rust's tools

#

In any case I'll show you my code if I make it work and then we re factor or you tell me how to do it better

#

Unless ofc I can't even finish it myself but I really hope I ain't that useless

#

Oh btw

#

Is there a way to add ram to a notebook?

#

Because I could do it if it's possible

#

I really want at least 8..

coral geyser
wary cloak
#

I see

#

How I know if mine can?

#

A bool in rust is only the keywords true or false or it can be 1 and 0?

wary cloak
#

Oh

#

Ok

coral geyser
wary cloak
#

What's the lowest interger type?

#

Because I need a variable that can only be 0 or 1 so in arduino I made it bool but here is an interger, so at least I'll anotate the smallest interger possible

robust mountainBOT
#
1
coral geyser
#

?eval 1 == 0

robust mountainBOT
#
false
wary cloak
#

Aside from that I have an issue, seems like nb::block gives back an u8

#

Not a character

#

And I should compare it to a character

#

Well I guess here it doesn't matter. .

#

Yeah I guess not

coral geyser
robust mountainBOT
#
97
coral geyser
#

?eval 97 as char

robust mountainBOT
#
'a'
wary cloak
#

So an u8 is the smallest interger possible?

coral geyser
wary cloak
#

Bruh I'm used to variables being mutable by default I forgot mut

coral geyser
#

?eval println!("{:b}", 42);

robust mountainBOT
#
101010
()
wary cloak
#

lcd.clear() was the method to clear?

coral geyser
#

yep

wary cloak
#

How was delay?

coral geyser
#

arduino_hal::delay_ms(...)

wary cloak
#

Thanks

#

Ok now I'm gonna show you the first bit of code the one that prints the first menu

#

Since well the other ones are gonna be basically the same

#

And you tell me if it looks fine for you or how can we re factor, make it better, more idiomatic rust or smth, idk, maybe it's fine as is, 0 error only 1 warning that I think is irrelevant

coral geyser
#

#![deny(warnings)] ferrisHotTake (joke)

wary cloak
#
#![no_std]
#![no_main]
mod lcd;
use crate::lcd::*;
use ::lcd::*;
use core::fmt::Write;
use arduino_hal::prelude::*;
use embedded_hal::prelude::_embedded_hal_serial_Read;

use panic_halt as _;

#[arduino_hal::entry]
fn main() -> ! {
    let dp = arduino_hal::Peripherals::take().unwrap();
    let pins = arduino_hal::pins!(dp);

    let mut confirmacion: u8 = 0;

    let mut serial = arduino_hal::Usart::new(
        dp.USART0,
        pins.d0,
        pins.d1.into_output(),
        arduino_hal::usart::Baudrate::new(57600),
    );

    let i2c = arduino_hal::I2c::new(
        dp.TWI,
        pins.d20.into_pull_up_input(),
        pins.d21.into_pull_up_input(),
        50000,
    );

    let lcd_conn = LcdConnection::new(i2c);

    let mut lcd = Display::new(lcd_conn);

    lcd.init(FunctionLine::Line2, FunctionDots::Dots5x8);
    lcd.display(
        DisplayMode::DisplayOn,
        DisplayCursor::CursorOff,
        DisplayBlink::BlinkOff);
    lcd.entry_mode(EntryModeDirection::EntryRight, EntryModeShift::NoShift);


    loop {
        lcd.position(3, 0);

        write!(&mut lcd, "Elija una bebida").unwrap();

        lcd.position(1, 1);

        write!(&mut lcd, "1-Fernet con Coca").unwrap();

        lcd.position(1, 2);

        write!(&mut lcd, "2-Sex on the beach").unwrap();

        lcd.position(1, 3);

        write!(&mut lcd, "3-Agua").unwrap();

        let tecla = nb::block!(serial.read()).void_unwrap();

        if tecla == 1{
            confirmacion = 1;
        } else if tecla == 2||tecla == 3 {
            lcd.clear();

            lcd.position(3, 0);

            write!(&mut lcd, "Bebida").unwrap();

            lcd.position(3, 1);

            write!(&mut lcd, "No disponible").unwrap();

            confirmacion = 0;

            arduino_hal::delay_ms(1000);
        }
    }
}
#

For now it's like that

#

Before the loop only new thing is the confirmacion variable

#

Ah.. I forgot an else for the not valid value when it isn't 1,2 or 3

#

Well anyways if that's fine the else I'm gonna add too

#

I will go add it in the meantime

#

Actually..

#

I also forgot the while loop

#

That breaks when confirmation is 1

coral geyser
# wary cloak ``` #![no_std] #![no_main] mod lcd; use crate::lcd::*; use ::lcd::*; use core::f...

Here is an idea

loop {
    lcd.position(0, 0);
    write!(&mut lcd, "{:^20}", "Elija una bebida").unwrap();

    lcd.position(0, 1);
    write!(&mut lcd, " 1-Fernet con Coca").unwrap();

    lcd.position(0, 2);
    write!(&mut lcd, " 2-Sex on the beach").unwrap();

    lcd.position(0, 3);
    write!(&mut lcd, " 3-Agua").unwrap();

    let tecla = nb::block!(serial.read()).void_unwrap();

    match tecla as char {
        '1' => confirmacion = 1,
        '2' | '3' => {
            lcd.clear();

            lcd.position(0, 0);
            write!(&mut lcd, "{:^20}", "Bebida").unwrap();

            lcd.position(0, 1);
            write!(&mut lcd, " No disponible").unwrap();

            confirmacion = 0;
            arduino_hal::delay_ms(1000);
        },
        _ => {},
    }
}
wary cloak
#

Tho thing is in arduino is an do while

#

And here does that even exist?

coral geyser
wary cloak
#

here is the else i was missing

coral geyser
#

Its cursed

wary cloak
#
else {
            lcd.clear();

            lcd.position(3, 0);

            write!(&mut lcd, "elija un").unwrap();

            lcd.position(3, 1);

            write!(&mut lcd, "valor valido").unwrap();

            confirmacion = 0;

            arduino_hal::delay_ms(1000);
        }
#

But I need a do while loop like in the original for this to be complete

#

Now I'll see what you came up with

wary cloak
#

Tho I don't understand why you use that weird center syntax if position already takes care of it

coral geyser
wary cloak
#

The catch all arm

coral geyser
#

yep

wary cloak
#

Could have that code

#

Perfect

#

Now that only thing is replacing the do while

#

So confirmation is actually useful

#

But first let me re factor with your solution

#

Ok I pass in the new version to make sure I did the changes correctly

#
#![no_std]
#![no_main]
mod lcd;
use crate::lcd::*;
use ::lcd::*;
use core::fmt::Write;
use arduino_hal::prelude::*;
use embedded_hal::prelude::_embedded_hal_serial_Read;

use panic_halt as _;

#[arduino_hal::entry]
fn main() -> ! {
    let dp = arduino_hal::Peripherals::take().unwrap();
    let pins = arduino_hal::pins!(dp);

    let mut confirmacion: u8 = 0;

    let mut serial = arduino_hal::Usart::new(
        dp.USART0,
        pins.d0,
        pins.d1.into_output(),
        arduino_hal::usart::Baudrate::new(57600),
    );

    let i2c = arduino_hal::I2c::new(
        dp.TWI,
        pins.d20.into_pull_up_input(),
        pins.d21.into_pull_up_input(),
        50000,
    );

    let lcd_conn = LcdConnection::new(i2c);

    let mut lcd = Display::new(lcd_conn);

    lcd.init(FunctionLine::Line2, FunctionDots::Dots5x8);
    lcd.display(
        DisplayMode::DisplayOn,
        DisplayCursor::CursorOff,
        DisplayBlink::BlinkOff);
    lcd.entry_mode(EntryModeDirection::EntryRight, EntryModeShift::NoShift);


    loop {
        lcd.position(0, 0);
        write!(&mut lcd, "Elija una bebida").unwrap();

        lcd.position(0, 1);
        write!(&mut lcd, " 1-Fernet con Coca").unwrap();

        lcd.position(0, 2);
        write!(&mut lcd, " 2-Sex on the beach").unwrap();

        lcd.position(0, 3);
        write!(&mut lcd, " 3-Agua").unwrap();

        let tecla = nb::block!(serial.read()).void_unwrap();
#
match tecla as char {
            '1' => confirmacion = 1,
            '2' | '3' => {
                lcd.clear();

                lcd.position(0, 0);
                write!(&mut lcd, "Bebida").unwrap();

                lcd.position(0, 1);
                write!(&mut lcd, " No disponible").unwrap();

                confirmacion = 0;
                arduino_hal::delay_ms(1000);
            },
            _ => {
                lcd.clear();

                lcd.position(3, 0);

                write!(&mut lcd, "elija un").unwrap();

                lcd.position(3, 1);

                write!(&mut lcd, "valor valido").unwrap();

                confirmacion = 0;

                arduino_hal::delay_ms(1000);
            },
        }
    }
}
#

Is it ok?

coral geyser
#

looks good

wary cloak
#

Ok so now the thing is the internal loop

#

See, in the original version

#

I used a do while so

#

It first executed this whole thing

#

And then asked for confirmation

#

How do we do it here?

#

Just for reference I'll show the cpp equivalent or what we are doing

coral geyser
wary cloak
#
void loop(){ 

  do{
    lcd.setCursor(3,0);
    lcd.print("Elija una bebida");
    lcd.setCursor(1,1);
    lcd.print("1-Fernet con Coca");
    lcd.setCursor(1,2);
    lcd.print("2-Sex on the beach");
    lcd.setCursor(1,3);
    lcd.print("3-Agua");
    tecla=keypad.waitForKey();
    if(tecla=='1'){
      confirmacion=1;
    }
    else if(tecla=='2'||tecla=='3'){
      lcd.clear();
      lcd.setCursor(3,0);
      lcd.print("Bebida");
      lcd.setCursor(3,1);
      lcd.print("No disponible");
      confirmacion=0;
      delay(1000);

    }
    else{
      lcd.clear();
      lcd.setCursor(3,0);
      lcd.print("elija un");
      lcd.setCursor(3,1);
      lcd.print("valor valido");
      confirmacion=0;
      delay(1000);
    }
  } while(confirmacion!=1);
wary cloak
coral geyser
wary cloak
#

Ohh

#

So

#

I get rid of confirmation and in the '1' arm I write break?

coral geyser
#

?eval break rust;

robust mountainBOT
#
error[E0425]: cannot find value `rust` in this scope
 --> src/main.rs:2:7
  |
2 | break rust;
  |       ^^^^ not found in this scope

error[E0268]: `break` outside of a loop
 --> src/main.rs:2:1
  |
2 | break rust;
  | ^^^^^^^^^^ cannot `break` outside of a loop

error: internal compiler error: It looks like you're trying to break rust; would you like some ICE?

note: the compiler expectedly panicked. this is a feature.

note: we would appreciate a joke overview: https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675

note: rustc 1.64.0-nightly (3924dac7b 2022-07-29) running on x86_64-unknown-linux-gnu

Some errors have detailed explanations: E0268, E0425.
For more information about an error, try `rustc --explain E0268`.
coral geyser
wary cloak
#

Well I had no error but I still have to check if it's done correctly

#

Well about the indentation of brackets idk but

#

I think it's okay

#

I'll send it again if it's okay to you we can already test if this works before moving forward

#

This time I'm only sending loop

#

You know the stuff before and that confirmation is gone now

#
loop {
        loop{
            lcd.position(0, 0);
            write!(&mut lcd, "Elija una bebida").unwrap();

            lcd.position(0, 1);
            write!(&mut lcd, " 1-Fernet con Coca").unwrap();

            lcd.position(0, 2);
            write!(&mut lcd, " 2-Sex on the beach").unwrap();

            lcd.position(0, 3);
            write!(&mut lcd, " 3-Agua").unwrap();

            let tecla = nb::block!(serial.read()).void_unwrap();

            match tecla as char {
                '1' => break,
                '2' | '3' => {
                    lcd.clear();

                    lcd.position(0, 0);
                    write!(&mut lcd, "Bebida").unwrap();

                    lcd.position(0, 1);
                    write!(&mut lcd, " No disponible").unwrap();

                    arduino_hal::delay_ms(1000);
                    },
                _ => {
                    lcd.clear();

                    lcd.position(3, 0);

                    write!(&mut lcd, "elija un").unwrap();

                    lcd.position(3, 1);

                    write!(&mut lcd, "valor valido").unwrap();

                    arduino_hal::delay_ms(1000);
                },
            }
        }
    }
}
coral geyser
#

looks good

wary cloak
#

Ok let's stop to think what would happen

#

So.

#

This should turn on

#

Write all that stuff that covers the four lines

#

And then wait for me to write whatever in the terminal

#

If 1 it exist the loop and then idk actually we should put a clear outside the loop or idk how can we tell

#

But if 2 or 3, print that it's not available and then come back to the other text and the same with any other value but it's just another message

#

So how do me test we exit the loop successfully with one?

#

Leaving that question I need to go dinner, I'll be back soon

coral geyser
wary cloak
#

Oh sure

#

Btw I'm back

#

Ok now I can test it

#

But first I need this again

#

cargo run -- --port COM6 -c

#

Mmm.. .

#

When it turns one that goes well

#

But say I send 4

#

It shows the text of unvalid value

#

Three times

#

A first and it quickly goes back to original text but then goes back to unvalid and then the original

#

And so 3 times

#

If I write 2

#

It does the same but it blinks also to the not valid portion

#

Drink not available, then the first 3 options, then unvalid value 3 times

#

It's a really weird behavior

coral geyser
#

Do you have to press enter in the terminal to send the number?

wary cloak
#

And one and one does unvalid value and then it prints the I left the loop thing I placed

wary cloak
coral geyser
#

the ravedude console doesn't filter out newlines

wary cloak
#

I don't get it

coral geyser
wary cloak
#

Why is that?

coral geyser
#

Because you press enter which is a character

wary cloak
#

And also it does it three times rather than two

#

Oh

#

Also

#

The centering is not working properly

coral geyser
wary cloak
#

Oh I'll solve it

#

Ok now I'll test the behavior again to make sure of something

#

I'll press 1 first and the re run

coral geyser
#
fn read_char(serial: &mut arduino_hal::usart::Usart) -> char {
    let mut last_char = ' ';
    loop {
        let current_char = nb::block!(serial.read()).void_unwrap() as char;
        if current_char == '\n' {
            return last_char;
        } else {
            last_char = current_char;
        }
    }
}
wary cloak
#

K

#

What it did was

#

First

#

It took a long time to react

#

Second

#

It excited the loop but then the unvalid value blink 2 times

#

So it's like it's taking 3 chars

#

The correct 1 and other 2

coral geyser
wary cloak
#

Probably

coral geyser
wary cloak
#

Two questions

#

First

#

I write it in place of nb::block and set tecla to the result of calling the function?

coral geyser
#
fn read_char(serial: &mut arduino_hal::usart::Usart) -> char {
    loop {
        let current_char = nb::block!(serial.read()).void_unwrap() as char;
        if current_char != '\n' && current_char != '\r' {
            return current_char;
        }
    }
}

this one should work with the \r\n

wary cloak
#

Second

#

Could you explain the function to me?

coral geyser
wary cloak
coral geyser
wary cloak
#

Why are there two US arts, what is each one?

coral geyser
#

US arts?

wary cloak
#

Usarts*

coral geyser
#

there is only one

wary cloak
#

&mut arduino_hal::usart::Usart

#
error[E0107]: missing generics for type alias `arduino_hal::Usart`
   --> src\main.rs:12:47
    |
12  | fn read_char(serial: &mut arduino_hal::usart::Usart) -> char {
    |                                               ^^^^^ expected 3 generic arguments
    |
note: type alias defined here, with 3 generic parameters: `USART`, `RX`, `TX`
   --> C:\Users\fuchi\.cargo\git\checkouts\avr-hal-f3855d5807fdfd57\1aacefb\arduino-hal\src\lib.rs:163:14
    |
163 |     pub type Usart<USART, RX, TX> = crate::hal::usart::Usart<USART, RX, TX, crate::DefaultClock>;
    |              ^^^^^ -----  --  --
help: add missing generic arguments
    |
12  | fn read_char(serial: &mut arduino_hal::usart::Usart<USART, RX, TX>) -> char {
    |                                               ~~~~~~~~~~~~~~~~~~~~

For more information about this error, try `rustc --explain E0107`.
coral geyser
wary cloak
#

What I mean is I want to understand the signature

#

Why are there two things called almost the same what is that me are receiving exactly

coral geyser
wary cloak
#

Oh ok so we are calling from the arduino hal abstraction the usart module that has the Usart struct

#

Why is USART a generic type?

coral geyser
wary cloak
#

And Usart would be the serial port or what exactly?

coral geyser
#

The mega has 4 usart devices

coral geyser
wary cloak
#

So usart is a serial port which the MEGA has four of the them and that's why USART is generic?

coral geyser
#
use embedded_hal::serial::Read;
fn read_char(serial: &mut impl Read<u8>) -> char {
    loop {
        let current_char = nb::block!(serial.read()).unwrap() as char;
        if current_char != '\n' && current_char != '\r' {
            return current_char;
        }
    }
}

this should fix the error

#

We can just use the trait Read instead

wary cloak
#

And you store in the variable current charity the value of nb::block which since it's an u8 you cast it to a char with as keyword, and the if makes sure you don't return anything else that the first only char, right?

coral geyser
#

yep

wary cloak
#

It's necessary to use Return? I thought in rust it wasn't necessary

coral geyser
wary cloak
#

Where?

coral geyser
wary cloak
#

Well there are more errors let me run cargo check

#
error[E0277]: `<impl Read<u8> as _embedded_hal_serial_Read<u8>>::Error` doesn't implement `Debug`
    --> src\main.rs:15:54
     |
15   |         let current_char = nb::block!(serial.read()).unwrap() as char;
     |                                                      ^^^^^^ `<impl Read<u8> as _embedded_hal_serial_Read<u8>>::Error` cannot be formatted using `{:?}` because it doesn't implement `Debug`
     |
     = help: the trait `Debug` is not implemented for `<impl Read<u8> as _embedded_hal_serial_Read<u8>>::Error`
note: required by a bound in `Result::<T, E>::unwrap`
    --> C:\Users\fuchi\.rustup\toolchains\nightly-2022-06-13-x86_64-pc-windows-msvc\lib\rustlib\src\rust\library\core\src\result.rs:1094:12
     |
1094 |         E: fmt::Debug,
     |            ^^^^^^^^^^ required by this bound in `Result::<T, E>::unwrap`
help: introduce a type parameter with a trait bound instead of using `impl Trait`
     |
13   | fn read_char<R: Read<u8>>(serial: &mut R) -> char where <R as _embedded_hal_serial_Read<u8>>::Error: Debug {
     |             +++++++++++++              ~          ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

warning: unused import: `embedded_hal::prelude::_embedded_hal_serial_Read`
 --> src\main.rs:8:5
  |
8 | use embedded_hal::prelude::_embedded_hal_serial_Read;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default
  = note: `#[warn(unused_imports)]` on by default

For more information about this error, try `rustc --explain E0277`.
warning: `rust_lcd` (bin "rust_lcd") generated 1 warning
coral geyser
#
use embedded_hal::serial::Read;
fn read_char(serial: &mut impl T: Read<u8>) -> char {
    loop {
        if let Ok(current_char) = nb::block!(serial.read()) {
            let current_char = current_char as char;
            if current_char != '\n' && current_char != '\r' {
                return current_char;
            }
        }
    }
}
coral geyser
wary cloak
#

What void thing?

coral geyser
#

the void_unwrap()

#

It's can't actually fail, but the trait is generic

wary cloak
#

I was later gonna ask about that

#

btw it says this is an unused import, do we get rid of it?

#
use embedded_hal::prelude::_embedded_hal_serial_Read;
coral geyser
#

yep

#

its actually the same thing as use embedded_hal::serial::Read;

wary cloak
#

But then why did we had to change it?

coral geyser
#

Because before we just needed it in scope to call .read(). Now we need to actually use the type name

wary cloak
#

No errors neither warnings so I'll test it

wary cloak
coral geyser
#

The impl Read<u8> says it will take anything that implements Read<u8>

#

basically you can read bytes from it

wary cloak
#

It works perfectly just that sometimes the answer takes time to arrive but maybe is my PC the thing

#

I have to enter my dogs home wait for me a little bit but anyways it works so we can finish the LCD programm now ig

#

I'm back

#

Oh ok I understand

#

Well now let's keep working

#

Tho

#

Yesterday I didn't ask you about how this whole serial port deal worked, in order to understand main 100% I need to ask

#

First

#
let mut serial = arduino_hal::Usart::new(
        dp.USART0,
        pins.d0,
        pins.d1.into_output(),
        arduino_hal::usart::Baudrate::new(57600),
    );
#

About this

#

First, what's the serial variable? The serial port of choice because the MEGA has four and we specificy inside we want to use the computer one?

coral geyser
#

And d0 and d1 are the pins it is connected to and the 57600 is the speed

wary cloak
#

Ok so you create a new instance or the Usart strict which we already stated what it was

#

But what's that of

#

dp.USART0?

coral geyser
#

of the 4

wary cloak
#

So that's telling use the serial port at 0 which is the computer one?

coral geyser
#

yep

wary cloak
#

I get the speed part because we talked about it before

#

But what are the other 2 pins for, what do they do if we said what port are we using? There's nothing conected to port 0 and 1

#

pin*

coral geyser
#

the chip the arrow is pointing to

wary cloak
#

So let's say they are needed for all serial communication so they are always gonna be the arguments of Usart new?

coral geyser
#

yep, at least for this project

wary cloak
#

So 0 receives data from the serial port and 1 sends it to the serial port of choice so because of that is an output, right?

coral geyser
#

yep

#

you will notice the TX and RX LEDs on the board flash when you send stuff over the USART0

#

as they are also connected to d0 and d1

wary cloak
#

Next line I wanted to talk about

#

ufmt::uwriteln!(&mut serial, "Sali del loop").void_unwrap();

#

What's ufmt it calls my attention

coral geyser
#

Its a smaller version of write!

wary cloak
#

But write! Wasn't for the LCD?

coral geyser
#

I think you can use write! on the Display, not 100% sure

#

try it out and see if it has an error

wary cloak
#

But we use write we don't use anything else

#

Remember today I said it called my attention that we used a macro and not an LCD method

#

Yesterday*

coral geyser
wary cloak
#

Why we use uwriteln? And what do you mean a smaller version?

coral geyser
wary cloak
#

What's ufmt? I guess fmt is from format, it's a library tho? A module?

coral geyser
wary cloak
#

So there's a library format and a micro format two separate ones?

coral geyser
wary cloak
#

fmt it's the one in core?

coral geyser
#

yep

wary cloak
#

And where's the other one from?

coral geyser
#

the ufmt library

wary cloak
coral geyser
wary cloak
#

So you could use both in place of one another?

coral geyser
#

yep,

wary cloak
#

Tho we never included fmt

#

Only fmt

#
mod lcd;
use crate::lcd::*;
use ::lcd::*;
use core::fmt::Write;
use arduino_hal::prelude::*;
use embedded_hal::serial::Read;
coral geyser
wary cloak
#

Sorry I mean

#

As you see there

#

We include write from fmt

#

But we never included

#

Ufmt

#

To use

coral geyser
#

ah, thats because we just named it directly with ufmt::...

wary cloak
#

So it's in the core too so there's no need to bring into scope while with fmt we did need to bring write macro into scope?

coral geyser
#

yeah

wary cloak
#

And I guess the u in uwriteln is for micro, and it's weird that one is just write and the other writeln but that's irrelevant

#

So it takes a mutable references to our serial port and the string it prints to it

#

I get that but

#

Why void_unwrap?

#

What does it do?

#

If it fails not panic but rather do nothing?

coral geyser
#
enum Void {}
#

Thats the definition of Void

#

Because it's an enum with no variants there is no way to make one

wary cloak
#

So uwriteln return a Result <T, Void> because it can never fail and we call instead of just unwrap, void_unwrap to take the T out of the result enum it gives back?

#

Why does it return a result type if literally you are doing nothing with it and go for the extra steps of extracting T?

coral geyser
wary cloak
#

Oh ok

#

Btw in the meantime of talking about this

#

I wrote the rest of the code

#

Let's see if it's done and it works

#

It perfectly works I just forgot about a detail

#

Yey :")

#

It's finished

#

I'll send it so you see it and tell if we refactor anything or there's room for improvement

#

Ok here

#
#![no_std]
#![no_main]
mod lcd;
use crate::lcd::*;
use ::lcd::*;
use core::fmt::Write;
use arduino_hal::prelude::*;
use embedded_hal::serial::Read;

use panic_halt as _;

fn read_char(serial: &mut impl Read<u8>) -> char {
    loop {
        if let Ok(current_char) = nb::block!(serial.read()) {
            let current_char = current_char as char;
            if current_char != '\n' && current_char != '\r' {
                return current_char;
            }
        }
    }
}

#[arduino_hal::entry]
fn main() -> ! {
    let dp = arduino_hal::Peripherals::take().unwrap();
    let pins = arduino_hal::pins!(dp);

    let mut serial = arduino_hal::Usart::new(
        dp.USART0,
        pins.d0,
        pins.d1.into_output(),
        arduino_hal::usart::Baudrate::new(57600),
    );

    let i2c = arduino_hal::I2c::new(
        dp.TWI,
        pins.d20.into_pull_up_input(),
        pins.d21.into_pull_up_input(),
        50000,
    );

    let lcd_conn = LcdConnection::new(i2c);

    let mut lcd = Display::new(lcd_conn);

    lcd.init(FunctionLine::Line2, FunctionDots::Dots5x8);

    lcd.entry_mode(EntryModeDirection::EntryRight, EntryModeShift::NoShift); 
#
loop {
        loop{
            lcd.display(
                DisplayMode::DisplayOn,
                DisplayCursor::CursorOff,
                DisplayBlink::BlinkOff);
            
            lcd.position(3, 0);
            write!(&mut lcd,"Elija una bebida").unwrap();

            lcd.position(1, 1);
            write!(&mut lcd, "1-Fernet con Coca").unwrap();

            lcd.position(1, 2);
            write!(&mut lcd, "2-Sex on the beach").unwrap();

            lcd.position(1, 3);
            write!(&mut lcd, "3-Agua").unwrap();

            let tecla = read_char(&mut serial);

            match tecla as char {
                '1' => break,
                '2' | '3' => {
                    lcd.clear();

                    lcd.position(3, 0);
                    write!(&mut lcd, "Bebida").unwrap();

                    lcd.position(3, 1);
                    write!(&mut lcd, "No disponible").unwrap();

                    arduino_hal::delay_ms(1000);
                    },
                _ => {
                    lcd.clear();

                    lcd.position(3, 0);

                    write!(&mut lcd,"elija un").unwrap();

                    lcd.position(3, 1);

                    write!(&mut lcd,"valor valido").unwrap();

                    arduino_hal::delay_ms(1000);
                },
            }
        }
        ufmt::uwriteln!(&mut serial, "Sali del primer loop").void_unwrap(); 
#
loop{
            lcd.clear();
            lcd.position(0, 0);
            write!(&mut lcd,"Elija la intensidad").unwrap();

            lcd.position(1, 1);
            write!(&mut lcd, "1-Suave").unwrap();

            lcd.position(1, 2);
            write!(&mut lcd, "2-Medio").unwrap();

            lcd.position(1, 3);
            write!(&mut lcd, "3-Fuerte").unwrap();

            let tecla = read_char(&mut serial);

            match tecla as char {
                '1' | '2' | '3' => break,
                _ => {
                    lcd.clear();

                    lcd.position(3, 0);

                    write!(&mut lcd,"elija un").unwrap();

                    lcd.position(3, 1);

                    write!(&mut lcd,"valor valido").unwrap();

                    arduino_hal::delay_ms(1000);
                },
            }
        }
        ufmt::uwriteln!(&mut serial, "Sali del segundo loop").void_unwrap();

        loop{
            lcd.clear();
            lcd.position(3, 1);
            write!(&mut lcd,"Preparando...").unwrap();

            lcd.display(
                DisplayMode::DisplayOn,
                DisplayCursor::CursorOn,
                DisplayBlink::BlinkOn);

                arduino_hal::delay_ms(10000);

                break;
        }
        ufmt::uwriteln!(&mut serial, "Sali del tercer loop").void_unwrap();
    }
} 
#

There

#

Tho I can remove the uwriteln now

#

As you'll see lcd.display it's move to loop because I want that the last thing is printed by the lcd which is a text for the period of time the drink is being served, I wanted the cursor to appear an blink so at the top of loop of put that so when it goes to the beginning again it goes away and remove it from main to avoid repetition

wary cloak
wary cloak
#

Oh and also I have two final questions about that code whenever it needs refactoring or not

#

Basically finish the understanding the serial port usage , we went through the serial variable and the uwriteln macro, but we still have to see the read one and also I want to see if I understand the if let statement you did because I have a hard time still understanding if let syntax

wary cloak
#
if let Ok(current_char) = nb::block! (Serial.read()) 
#

I'll leave it here for later

old mango
# wary cloak ```rust if let Ok(current_char) = nb::block! (Serial.read()) ```

This syntax means 'do nb::block!(Serial.read()) and if it results in an Ok, take what's inside the Ok as the variable current_char, and make current_char available within the if block'
The if let X(y) = <expression> { <operations with y> } syntax is basically equivalent to

match <expression> {
  X(y) => { <operations with y> }
  _ => ()
}
wary cloak
#

Thank you

wary cloak
#

Tho aside from understanding the if let syntax the other thing I wanted was to ask for how nb::block!(Serial.read()) worked

wary cloak
#

@coral geyser good afternoon (I think?) are you available?

coral geyser
#

👋 for a little bit

wary cloak
#

Oh

#

How about later then, will you be? So I free myself when you are

coral geyser
#

Later today I am busy, just thought I would pop in to the discord and answer some questions between tasks

wary cloak
#

Oh, well I'm going to sleep early because I have school tomorrow but I hope coincidentally with the hour difference I get to see you a little bit free

#

Well then if you have a little bit of time

#

I have two questions primarily

#

The code above works as intended, but do you have any feedback on how to do it better or refactor it just like when you changed my if else to match? Or you would leave it like that?

coral geyser
wary cloak
#

So the main_menu(to call it different to the next one) select menu and wait menu?

#

Tho in future parts of the project there will be more selection menus so, it will work only for now to call it main menu

#

So I create three functions in another module, copy paste the code is have in them , import it, and merely call them in main?

#

I have*

coral geyser
wary cloak
# coral geyser Yep

What would the signature be, they will all take mutable references to lcd, and return nothing?

coral geyser
wary cloak
#

And I can call display for the setup like I did with no problem inside them, right?

#

And also, I would create a module or a library crate to do this? And how should it be called? I propose we maybe should call the lcd module (which takes cares of the I2C) I2C and this new module lcd maybe

coral geyser
wary cloak
#

Why not now?

#

Any particular reason?

coral geyser
#

No, you can put them were ever you want. General rule is to refactor in small moves

wary cloak
#

Oh so maybe when I prove they work as intended I could do that?

#

And also are you fine with the name changes or are they wrong?

coral geyser
wary cloak
#

The new functions should also be in a module or should they be in a library crate?

coral geyser
#

You probably don't need any custom library crates for this project

wary cloak
#

When do you know if a library or a module is needed?

coral geyser
wary cloak
#

Also, when we do the last step remaining which is you now the function to stop making things manually and so, will it also be in it's own module?

wary cloak
coral geyser
wary cloak
#

I mean I could ask you to teach and we can work there but wouldn't it be a pain?

coral geyser
#

Yeah probably

wary cloak
#

And also can you run code there or we will use it just to save the code?

coral geyser
#

I would just copy all the code when you make a new project

wary cloak
coral geyser
#

It should be easier the manage than making library crates

wary cloak
coral geyser
wary cloak
#

I think I don't have the criteria to know that yet

#

My code it's messy

#

Well then what could we call the functions?

#

Last one is waiting screen

#

But the first two are both selection screens

#

Maybe.. Yeah, select drink, select intensity

#

Well after doing that of the functions and let's imagine my code works again like intended

#

Would you do anything else or we could go to the last step?

coral geyser
wary cloak
#

Aaaah yeah that I forgot

#

I don't get that about problem with states and what a state machine is and all that

#

And also that says C, C++ is just for knowing the concept?

coral geyser
#

Basically you would have like an enum saying which screen (state) you are in. And one loop that moves between states

wary cloak
#

Oh ok

#

So..

#

An enum

#

With all my states

#

Like, waiting, select drink, select intensity

#

And my loop single loop which ask the state and execute the function depending on the state and at the end of each function I change the state to call the next function?

coral geyser
#

Yep, it may also contain things like: the drink selected after you enter it, the intensity after you enter it...

wary cloak
#

I think I will need help for that so I'll leave it for later, but the functions in it's own module I'll do it in a little bit

#

The other question I had beside the whole refactoring was

coral geyser
#
struct App {
  state: State,
  selected_drink: Drink,
  amount: u8,
  ...
}
wary cloak
#

That line

#

So I can finally understand all we do with the serial port

#

First, what's nb? A module, a library?

coral geyser
wary cloak
coral geyser
#

It provides no-block (nb) input/output APIs

wary cloak
coral geyser
#

So like in the Arduino code you know how you have the available byte count on the serial to see if there is stuff to read?

wary cloak
#

Yeah, what that does is ask if there's something to read and if 0 there's nothing yet so I used in while with the condition it had to be bigger than 0

coral geyser
#

The serial.read() can return a nb::Error::WouldBlock

#

This signals that there isn't anything to read yet

#

The block!() macro just waits for this to become an actual value

wary cloak
#

So serial read does the same as serial available and while it has nothing to read it returns an error and when it receives something it return it?

wary cloak
coral geyser
wary cloak
#

The last thing I would like to ask before jumping into code again aside from how to do the state machine exactly (which I would the code in front of me from and Start doing stuff which would take time) was to go over the lcd module we made so I could understand what we did with I2C to understand to protect to it's fullest it's not a long code but idk if this will take long or not so if you think is too much we could do it for later that also

coral geyser
#

I need to get going now

wary cloak
#

Oh well good look, I hope I see you later before I go to sleep so maybe maybe we could finally get the lcd 100% done, in the meantime I will do the functions and update here if they worked or what happened

#

Luck*

wary cloak
#

I am doing the functions and so

#

and got like millions errors

#

I thought the argument should be a mutable reference to the lcd we defined

#

so I wrote all signatures like this

#

fn show_drinks(lcd: &mut lcd)

#

It seems it doesn't work

#

But then I saw when you made an example

#

You made this the parameter

#

lcd: &mut Display<LcdConnection>

#

I have no clue why and why mine's wrong but I'll see if writing it that way fixes all the errors because it seems they mostly have to do with scope and the setup I did in main missing there is as if I had to copy everything from main and main would only have the call to that functions

#

Well maybe my signature wasn't incorrect

#

Thing is..

#

I should take everything from main and place it there? Even the dp definition? But then I wouldn't be able to work in main with other components without dp and pins

#

I don't understand I copied dp, pins, serial definition, i2c, definition, ldc_conn definition, and lcd and lcd.init, entry mode

#

Everything

#

And it's full of errors

#

It seems that kind of thing in which the error is really stupid but I don't get what's happening

#

I imported some use statements I see if I need more and that help solve some of them

#

Well there are still erorrs I can't understand

#

I'm making this follow up just in case

#

I got rid of the module it couldn't find that worked for some reason and I for rid of all the copying of the variables like dp and so

#

But then it said can't find serial so ok I brought serial definition

#

And now this

#

Idk what's an item

#

And why here let it's supposedly wrong and not before

#

Is a variable after all

#

And i don't also now what's "BANG"

wary cloak
#
error: expected item, found keyword `let`
  --> src\lcd.rs:19:1
   |
19 | let mut serial = arduino_hal::Usart::new(
   | ^^^ expected item

error: could not compile `rust_lcd` due to previous error
PS C:\Users\fuchi\OneDrive\Documentos\Codigos_Rust\rust_lcd> cargo check
    Checking rust_lcd v0.1.0 (C:\Users\fuchi\OneDrive\Documentos\Codigos_Rust\rust_lcd)
error: expected item, found keyword `let`
  --> src\lcd.rs:18:1
   |
18 | let mut serial = arduino_hal::Usart::new(
   | ^^^ expected item

error: could not compile `rust_lcd` due to previous error
#

I think this is as far as I can get I can't make sense of this error

#

Just for the record if that helps

#

I haven't deleted anything from main just copied it here until it worked and then I could try but I don't think that has to do

wary cloak
#

Well I need to go to sleep already sadly-

#

Gn

old mango
#

In fact, a lot of your errors just like stuff that should be inside functions being outside functions

#

I think in this case, the 'expected BANG' thing is the same; bang refers to the ! character, so i think rust saw identifiers in the top-level scope and assumed they were macros (and thus expected them to end with a !), but got confused when there wasn't any

wary cloak
#

And since I can't declare for example serial outside the function I couldn't use it

#

So maybe I could declare serial at the beginning of the function that uses it

#

Or create another main which would be weird for a module to extract code from the main function-

#

And turn it into functions too

old mango
#

What might be better (not sure how the hal handles things) is to create the serial in your main, and then just pass a ref of that to all the functions that need it
Since it feels like reopening the serial line in every function could be problematic

wary cloak
#

Oh that could work :o

#

I'll see if I can also pass a reference to serial to the functions that needed

#

Thank you when I'm back from school I'll try that, and also now I know that I can't declare variables outside a function so I should pass references to things declared in main

#

Since you are here, could you more or less explain to me the state machine thing? The one who's helping me told I had a problem with state, which loop my programm is in, and I should do a state machine that was like an enum that tracked the state of my programm or idk, smth like that and even made a little example but I don't know exactly what to do, how to implement it

#

You could scroll up to see well the code (basically it's still like that excepting for the module I was trying to do to make it more readable and the I2C module which is irrelevant for this situation)

old mango
old mango
# wary cloak Since you are here, could you more or less explain to me the state machine thing...

I think this is just thinking of your program as a set of states it can be in, and a loop where each iteration moves from one state to another
So for example, you might go from State::DisplayingMainMenu to State::PouringDrink(DrinkType::Agua, /* amount: */12) based on the result of your show_main_menu function or whatever you have
The above would be an example where the state is an enum, where each variant (and its associated info) is a state; of course, there are different ways to distribute that information; for instance, you might move certain variables that are common to most/all states into a struct that wraps the state enum, as i believe madfrog suggested earlier, but the exact form that takes is whatever you think will support the operations you need your program to perform
So basically you have a loop of «initial state -> perform operation appropriate for that state -> set new state based on the result of that operation -> perform operation appropriate for that state -> ...»

#

Anyway, I'm heading off to sleep; buena suerte con el proyecto!

wary cloak
#

Tho I will needed to go over the state machine in code to see if I understand

#

I understand the concept

#

Maybe not so much how you apply it

wary cloak
#

@coral geyser are you up for today? (Is that a valid english expression?)

wary cloak
#

Not me :(

#

I have my grandpas birthday

#

I may have some time to work if I stay awake a bit idk when it's ending but not that late

#

I reaaaally hope you can still be here by then

#

In the meantime well

#

I had some issues with the module but maybe by passing a reference to serial it's resolved I hope

#

And yeah I get the concept but I will need help to actually implement a state machine

wary cloak
#

And well then the only thing left is making this function in rust to have it even easier to use it later

#
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'}

    );

wary cloak
#

Well I'm gonna try my hardest to come as soon as possible

#

Because really after the lcd everything left for base functionality is fairly easy and quick or that it seems so I could still get it by Wednesday if God is by my side(?

coral geyser
wary cloak
#

Enjoy it, and good luck

#

I hope to see you soon

wary cloak
#

@coral geyser I came back, now I have a decent amount of time

coral geyser
#

I broke my Gentoo install so I am just working on that now

wary cloak
#

Gentoo?

coral geyser
#

Its a form of linux

wary cloak
#

Oh

#

Well just tell me when you are free I guess I have maybe.

#

2 hours maybe

coral geyser
#

I am free to answer questions

#

I have a backup OS for these occasions

wary cloak
#

Wow

#

Programmers do be prepared

#

Have you seen more or less what I had tried to do and failed miserably?

coral geyser
#

I sort of need it as I compile my own linux kernels 😅

coral geyser
wary cloak
#

I'm gonna try what that gentleman said

#

Of pasing a mutable reference to serial

#

To all those functions

#

To see if maybe that was it

#

But well if it doesn't work I'll ask you

#

Btw I have decided

#

I will soon by the raspberry Pi pick

#

Pico*

#

But the last models with wifi and Bluetooth don't enter the country :(

#

That's a huge disappointment for me.

coral geyser
wary cloak
#

Also I don't get why some cost 1500 pesos and some others 5000 what it's the difference if there's only one

#

So I'm doubtful about what to buy

wary cloak
coral geyser
#

That I have no idea. I have only every bought them off the official partner sites

coral geyser
#

Very easy to get going with it

wary cloak
#

How different is from regular python?

coral geyser
#

Not that different, mostly the standard you don't have access to the "normal" python stuff

#

Which basically all embedded languages suffer from

wary cloak
#

Mmm

#

But if you know python you grab it easy?

coral geyser
#

yeah, definitely

wary cloak
#

Do you like programming on it?

coral geyser
#

My tastes in embedded languages doesn't align well with micro python. I prefer very close to assembly if not actual assembly. So Rust fits nicely

#

Plus I do to much Python at work

wary cloak
#

Tho I heard you can

#

Program in micro python, in C++ or with the Arduino IDE with extra stuff, and most of the libraries work in raspberry Pi

#

So you can have all raspberry power and feek like home

#

Feel*

coral geyser
#

yep, they have done good allowing the use of other libraries

wary cloak
#

Tho idk how hard it is or how so you do it, and also how's the C++ programming option they have

#

Tho I'm interested in micro python for fun

#

I want you to help me actually get the Arduino ide there really

#

And also.. Could I use this abstraction we are using? I want the powerful raspberry Pi pico and rust

#

Actually if I could (and I'm thinking about it) I would pass my project not only to rust but to the raspberry Pi pico if has the chance

coral geyser
#

So it wouldn't be that hard to switch

wary cloak
#

But you mean

#

A raspberry Pi abstraction?

#

Because I was talking about since we can use the Arduino IDE there idk keep using Arduino hal?

coral geyser
#

But they both share the embedded_hal library so they have basically the same interface as each other in the rust code

wary cloak
#

Oh

#

Mmm well it also depends if I have enough pins because for example mega has like

#

5 Vcc and GND more or less

#

And also raspberry Pi is so powerful to endure something as heavy as python that rust is merely too godlike there

#

What would be the type of serial?

#

Ah yes also one thing I said earlier why in the signature of the function you placed lcd: &mut Display <LcdConnection> instead of lcd: &mut lcd?

coral geyser
wary cloak
#

Oh you need the type

coral geyser
#

yep

wary cloak
#

What would be the type of serial?

#

Because that didn't work

coral geyser
#

For the serial one do &mut impl Write<u8>

#

like the Read one

#

It's full type is long

wary cloak
#

For god's sake it's resisting so much

coral geyser
# wary cloak

You probably have another Write trait in scope. We want the embedded_hal::serial::Write one

wary cloak
#

All this of abstracting the functions logic from main

coral geyser
#

remove the core::fmt::Write for now

wary cloak
#

Resulted way more difficult that I expected

wary cloak
coral geyser
wary cloak
#

It says it can't find trait write

coral geyser
wary cloak
coral geyser
#

or use embedded_hal::serial::{Write, Read};

#

to combine them together

wary cloak
#

Btw is it possible to use concurrenry or async await(which I don't know what is) in embedded systems? Or is too costly for memory or it wouldn't make sense?

coral geyser
wary cloak
#

How many errors aaaaa

coral geyser
wary cloak
#
error[E0425]: cannot find value `serial` in this scope
  --> src\lcd.rs:84:36
   |
84 |         let tecla = read_char(&mut serial);
   |                                    ^^^^^^ not found in this scope

warning: unused import: `arduino_hal::prelude::*`
 --> src\lcd.rs:4:5
  |
4 | use arduino_hal::prelude::*;
  |     ^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

error[E0277]: the trait bound `&mut impl Read<u8>: _embedded_hal_serial_Read<u8>` is not satisfied
  --> src\lcd.rs:37:31
   |
37 |         let tecla = read_char(&mut serial);
   |                     --------- -^^^^^^^^^^
   |                     |         |
   |                     |         the trait `_embedded_hal_serial_Read<u8>` is not implemented for `&mut impl Read<u8>`
   |                     |         help: consider removing the leading `&`-reference
   |                     required by a bound introduced by this call
   |
note: required by a bound in `lcd::read_char`
  --> src\lcd.rs:7:32
   |
7  | fn read_char(serial: &mut impl Read<u8>) -> char {
   |                                ^^^^^^^^ required by this bound in `lcd::read_char`

For more information about an error, try `rustc --explain E0277`.
warning: `rust_lcd` (bin "rust_lcd") generated 1 warning
error: could not compile `rust_lcd` due to 2 previous errors; 1 warning emitted
coral geyser
wary cloak
#

The thing is until it doesn't work in the first one I wasn't going to import it to the other functions

#

But well now I implemented it on all or the them

coral geyser
wary cloak
#

Yes

#

I shall remove ir

#

It*

#

It still the unused import and that write is no longer found for the write! Because we erased it earlier

coral geyser
#

oh, looking at the docs Display only implements core::fmt::Write ferrisSob

#

okay nevermind

#

do use core::fmt::Write as _;

wary cloak
#

Why the as?

coral geyser
#

that will bring it into scope without clashing with the other Write

wary cloak
#

Cargo check again

#
warning: unused import: `arduino_hal::prelude::*`
 --> src\lcd.rs:3:5
  |
3 | use arduino_hal::prelude::*;
  |     ^^^^^^^^^^^^^^^^^^^^^^^ 
  |
  = note: `#[warn(unused_imports)]` on by default

error[E0277]: the trait bound `&mut impl Write<u8>: _embedded_hal_serial_Read<u8>` is not satisfied
  --> src\lcd.rs:37:31
   |
37 |         let tecla = read_char(&mut serial);
   |                     --------- ^^^^^^^^^^^ the trait `_embedded_hal_serial_Read<u8>` is not implemented for `&mut impl Write<u8>`
   |                     |
   |                     required by a bound introduced by this call
   |
   = help: the following other types implement trait `_embedded_hal_serial_Read<Word>`:
             avr_hal_generic::usart::Usart<H, USART, RX, TX, CLOCK>
             avr_hal_generic::usart::UsartReader<H, USART, RX, TX, CLOCK>
note: required by a bound in `lcd::read_char`
  --> src\lcd.rs:7:32
   |
7  | fn read_char(serial: &mut impl Read<u8>) -> char {
   |                                ^^^^^^^^ required by this bound in `lcd::read_char`

error[E0277]: the trait bound `&mut impl Write<u8>: _embedded_hal_serial_Read<u8>` is not satisfied
  --> src\lcd.rs:84:31
   |
84 |         let tecla = read_char(&mut serial);
   |                     --------- ^^^^^^^^^^^ the trait `_embedded_hal_serial_Read<u8>` is not implemented for `&mut impl Write<u8>`
   |                     |
   |                     required by a bound introduced by this call
   |
   = help: the following other types implement trait `_embedded_hal_serial_Read<Word>`:
             avr_hal_generic::usart::Usart<H, USART, RX, TX, CLOCK>
             avr_hal_generic::usart::UsartReader<H, USART, RX, TX, CLOCK>
note: required by a bound in `lcd::read_char`
  --> src\lcd.rs:7:32
   |
7  | fn read_char(serial: &mut impl Read<u8>) -> char {
   |                                ^^^^^^^^ required by this bound in `lcd::read_char`

For more information about this error, try `rustc --explain E0277`.
coral geyser
wary cloak
#

Done

coral geyser
#

It should also be the embedded_hal::serial::Read

wary cloak
#

Maybe(?

wary cloak
coral geyser
coral geyser
wary cloak
#
let tecla = read_char(&mut serial);```
coral geyser
wary cloak
#
fn show_drinks(lcd: &mut Display<LcdConnection>, serial: &mut impl Write<u8>) {
    loop{
        lcd.display(
            DisplayMode::DisplayOn,
            DisplayCursor::CursorOff,
            DisplayBlink::BlinkOff);
        
        lcd.position(3, 0);
        write!(&mut lcd,"Elija una bebida").unwrap();

        lcd.position(1, 1);
        write!(&mut lcd, "1-Fernet con Coca").unwrap();

        lcd.position(1, 2);
        write!(&mut lcd, "2-Sex on the beach").unwrap();

        lcd.position(1, 3);
        write!(&mut lcd, "3-Agua").unwrap();

        let tecla = read_char(&mut serial);

        match tecla as char {
            '1' => break,
            '2' | '3' => {
                lcd.clear();

                lcd.position(3, 0);
                write!(&mut lcd, "Bebida").unwrap();

                lcd.position(3, 1);
                write!(&mut lcd, "No disponible").unwrap();

                arduino_hal::delay_ms(1000);
                },
            _ => {
                lcd.clear();

                lcd.position(3, 0);

                write!(&mut lcd,"elija un").unwrap();

                lcd.position(3, 1);

                write!(&mut lcd,"valor valido").unwrap();

                arduino_hal::delay_ms(1000);
            },
        }
    }
}
coral geyser
#

ummm

#

&mut impl Write<u8> + Read<u8>

#

in the definition of show_drinks

wary cloak
#

Ambiguos + type

#

I'll run cargo check then

coral geyser
#

Sorry, I am basing this all off the docs. So it's difficult to figure out exactly which ones you need where

wary cloak
#

this is not all but a part i guess i will do that

#
fn show_intensity(lcd: &mut Display<LcdConnection>, serial: &mut impl Write<u8> + Read<u8>) {
   |                                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(impl Write<u8> + Read<u8>)`

error: ambiguous `+` in a type
   --> src\lcd.rs:104:71
    |
104 | fn show_waiting_screen(lcd: &mut Display<LcdConnection>, serial: &mut impl Write<u8> + Read<u8>) {
    |                                                                       ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(impl Write<u8> + Read<u8>)`
wary cloak
#

I'm only midly concern of not knowing for certain what I'm doing maybe

coral geyser
wary cloak
#

Done there's one error left

#

Two but it's the same

#
error[E0277]: the trait bound `&mut impl Write<u8> + Read<u8>: _embedded_hal_serial_Read<u8>` is not satisfied
  --> src\lcd.rs:36:31
   |
36 |         let tecla = read_char(&mut serial);
   |                     --------- -^^^^^^^^^^
   |                     |         |
   |                     |         the trait `_embedded_hal_serial_Read<u8>` is not implemented for `&mut impl Write<u8> + Read<u8>`
   |                     |         help: consider removing the leading `&`-reference
   |                     required by a bound introduced by this call
   |
note: required by a bound in `lcd::read_char`
  --> src\lcd.rs:6:32
   |
6  | fn read_char(serial: &mut impl Read<u8>) -> char {
   |                                ^^^^^^^^ required by this bound in `lcd::read_char`

error[E0277]: the trait bound `&mut impl Write<u8> + Read<u8>: _embedded_hal_serial_Read<u8>` is not satisfied
  --> src\lcd.rs:83:31
   |
83 |         let tecla = read_char(&mut serial);
   |                     --------- -^^^^^^^^^^
   |                     |         |
   |                     |         the trait `_embedded_hal_serial_Read<u8>` is not implemented for `&mut impl Write<u8> + Read<u8>`
   |                     |         help: consider removing the leading `&`-reference
   |                     required by a bound introduced by this call
   |
note: required by a bound in `lcd::read_char`
  --> src\lcd.rs:6:32
   |
6  | fn read_char(serial: &mut impl Read<u8>) -> char {
   |                                ^^^^^^^^ required by this bound in `lcd::read_char`

For more information about this error, try `rustc --explain E0277`.
wary cloak
#

Oh no-

#

But I don't understand why it worked in main but here is so god damn hard

coral geyser
#

That is actually a good point

wary cloak
#

It seems that the only issue is the fact that we need to use the serial ports in this functions

#

In main it's declared

#

And just used

#

Here a function is created so new scope

#

And we need serial

#

Now the thing is, why the hell is that hard

#

Also we aren't using it directly

#

We are using it via read_char

#

Which it's fine and it works on it's own

coral geyser