Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testing Enhancements #36

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
15 changes: 6 additions & 9 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@ jobs:
cargo build --release --target armv7-unknown-linux-gnueabihf
mkdir $BUILD_NAME
mv target/armv7-unknown-linux-gnueabihf/release/odyssey $BUILD_NAME
cp default.yaml $BUILD_NAME
cp apiHelper.py $BUILD_NAME
tar -czvf $BUILD_NAME.tar.gz -C $BUILD_NAME odyssey apiHelper.py default.yaml
cp resources/default.yaml $BUILD_NAME
tar -czvf $BUILD_NAME.tar.gz -C $BUILD_NAME odyssey default.yaml

- name: upload armv7 artifact
uses: actions/upload-artifact@v4.3.1
Expand All @@ -47,9 +46,8 @@ jobs:
cargo build --release --target aarch64-unknown-linux-gnu
mkdir $BUILD_NAME
mv target/aarch64-unknown-linux-gnu/release/odyssey $BUILD_NAME
cp default.yaml $BUILD_NAME
cp apiHelper.py $BUILD_NAME
tar -czvf $BUILD_NAME.tar.gz -C $BUILD_NAME odyssey apiHelper.py default.yaml
cp resources/default.yaml $BUILD_NAME
tar -czvf $BUILD_NAME.tar.gz -C $BUILD_NAME odyssey default.yaml

- name: upload aarch64 artifact
uses: actions/upload-artifact@v4.3.1
Expand All @@ -63,9 +61,8 @@ jobs:
cargo build --release --target x86_64-unknown-linux-gnu
mkdir $BUILD_NAME
mv target/x86_64-unknown-linux-gnu/release/odyssey $BUILD_NAME
cp default.yaml $BUILD_NAME
cp apiHelper.py $BUILD_NAME
tar -czvf $BUILD_NAME.tar.gz -C $BUILD_NAME odyssey apiHelper.py default.yaml
cp resources/default.yaml $BUILD_NAME
tar -czvf $BUILD_NAME.tar.gz -C $BUILD_NAME odyssey default.yaml

- name: upload x86_64 artifact
uses: actions/upload-artifact@v4.3.1
Expand Down
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ itertools = "0.12.1"
png = "0.17.7"
framebuffer = "0.3.1"
tokio = { version = "1", features = ["full"] }
tokio-serial = "5.4.4"
futures = "0.3.26"
async-trait = "0.1.64"
regex = "1"
Expand All @@ -25,3 +26,7 @@ poem-openapi = { version = "5.0.0", features = ["swagger-ui"] }
glob = "0.3.1"
log = "0.4.17"
simple_logger = "4.1.0"

[dev-dependencies]
tempfile = "3.13.0"
nix = { version = "0.29.0", features = ['fs'] }
10 changes: 8 additions & 2 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,22 @@ use std::path::Path;

const CONFIG_FILE: &str = "default.yaml";
const API_HELPER_FILE: &str = "apiHelper.py";
const RESOURCES: &str = "resources";
const SCRIPTS: &str = "scripts";

fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap();
let cargo_dir = env::var_os("CARGO_MANIFEST_DIR").unwrap();
fs::copy(
CONFIG_FILE,
Path::new(&cargo_dir).join(RESOURCES).join(CONFIG_FILE),
Path::new(&out_dir).join("../../..").join(CONFIG_FILE),
)
.unwrap();
fs::copy(
API_HELPER_FILE,
Path::new(&cargo_dir)
.join(RESOURCES)
.join(SCRIPTS)
.join(API_HELPER_FILE),
Path::new(&out_dir).join("../../..").join(API_HELPER_FILE),
)
.unwrap();
Expand Down
File renamed without changes.
File renamed without changes.
14 changes: 4 additions & 10 deletions test/fbEmulator.py → resources/scripts/fbEmulator.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
#!/usr/bin/env python3
import os
import glob
import pygame
import io

fifo_path = "/tmp/emulatedFramebuffer"
fifo_path = glob.glob("/tmp/odysseyTest*/emulatedFramebuffer")[0]
mode = 0o600

try:
os.mkfifo(fifo_path, mode=mode)
except OSError as e:
print("FIFO creation error:", e)
print("Continuing.")

real_bit_depth=[5,6,5]

bytes_per_pixelgroup=int(sum(real_bit_depth)/8)
Expand All @@ -23,7 +16,7 @@
#zoom_ratio=1

sliced_x, sliced_y = (192,108)
zoom_ratio=10
zoom_ratio=1


print(f"Rendering a screen {sliced_x*zoom_ratio}x{sliced_y*zoom_ratio}")
Expand All @@ -43,6 +36,7 @@
frame_size=int((sliced_x*sliced_y)*(bytes_per_pixelgroup/len(real_bit_depth)))

with open(fifo_path, mode='rb', buffering=frame_size) as efb:
efb.read()
while True:
if efb.readable():
data = efb.read()
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,18 @@
let mut new_buffer: Vec<u8> = Vec::new();

buffer
.chunks_exact(pixels_per_chunk.into())
.chunks_exact(pixels_per_chunk)
.for_each(|pixel_chunk| {
// raw binary chunk of pixels, to be broken into bytes and repacked in the Vector later
let mut raw_chunk = 0b0;
let mut pos_shift = chunk_size;
for i in 0..pixels_per_chunk {

Check warning on line 60 in src/display.rs

View workflow job for this annotation

GitHub Actions / lint

the loop variable `i` is used to index `pixel_chunk`
let depth_difference = bit_depth - self.config.bit_depth[i];
pos_shift -= self.config.bit_depth[i];

// Truncate the pixel data to the display's bit depth, then shift it into place in the raw chunk
let shifted_pixel: u64 =
((pixel_chunk[i as usize] as u64) >> depth_difference) << (pos_shift);
((pixel_chunk[i] as u64) >> depth_difference) << (pos_shift);
raw_chunk |= shifted_pixel;
}

Expand Down
95 changes: 28 additions & 67 deletions src/gcode.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use core::panic;
use std::collections::HashMap;
use std::io::{self, BufRead, BufReader, Error, ErrorKind, Write};
use std::io::{Error, ErrorKind};

use async_trait::async_trait;
use regex::Regex;
use serialport::{ClearBuffer, SerialPort, SerialPortBuilder, TTYPort};
use tokio::sync::mpsc::{self, Receiver, Sender};
use tokio::sync::broadcast;
use tokio::time::{interval, sleep, Duration};

use crate::api_objects::PhysicalState;
Expand All @@ -16,22 +15,16 @@ pub struct Gcode {
pub config: GcodeConfig,
pub state: PhysicalState,
pub gcode_substitutions: HashMap<String, String>,
pub serial_port: TTYPort,
pub transceiver: (Sender<String>, Receiver<String>),
pub serial_receiver: broadcast::Receiver<String>,
pub serial_sender: broadcast::Sender<String>,
}

impl Gcode {
pub fn new(config: Configuration, serial_builder: SerialPortBuilder) -> Gcode {
let transceiver = mpsc::channel(100);
let mut port = serial_builder
.open_native()
.expect("Unable to open serial connection");

port.set_exclusive(false)
.expect("Unable to set serial port exclusivity(false)");
port.clear(ClearBuffer::All)
.expect("Unable to clear serialport buffers");

pub fn new(
config: Configuration,
serial_receiver: broadcast::Receiver<String>,
serial_sender: broadcast::Sender<String>,
) -> Gcode {
Gcode {
config: config.gcode,
state: PhysicalState {
Expand All @@ -40,36 +33,8 @@ impl Gcode {
curing: false,
},
gcode_substitutions: HashMap::new(),
serial_port: port,
transceiver,
}
}

pub async fn run_listener(port: TTYPort, sender: Sender<String>) {
let mut buf_reader = BufReader::new(port);
let mut interval = interval(Duration::from_millis(100));

loop {
interval.tick().await;
let mut read_string = String::new();
match buf_reader.read_line(&mut read_string) {
Err(e) => match e.kind() {
io::ErrorKind::TimedOut => {
continue;
}
// Broken Pipe here
other_error => panic!("Error reading from serial port: {:?}", other_error),
},
Ok(n) => {
if n > 0 {
log::debug!("Read {} bytes from serial: {}", n, read_string.trim_end());
sender
.send(read_string)
.await
.expect("Unable to send message to channel");
}
}
};
serial_receiver,
serial_sender,
}
}

Expand All @@ -94,12 +59,10 @@ impl Gcode {
let parsed_code = self.parse_gcode(code) + "\r\n";
log::debug!("Executing gcode: {}", parsed_code.trim_end());

let n = self.serial_port.write(parsed_code.as_bytes())?;
self.serial_port
.flush()
.expect("Unable to flush serial connection");
self.serial_sender
.send(parsed_code)
.map_err(|error| Error::new(ErrorKind::BrokenPipe, error))?;

log::trace!("Wrote {} bytes", n);
// Force a delay between commands
sleep(Duration::from_millis(100)).await;
Ok(())
Expand Down Expand Up @@ -130,18 +93,23 @@ impl Gcode {

// Consume all available responses in case of ack messages before desired
async fn check_response(&mut self, response: &String) -> bool {
let mut has_response = self
.transceiver
.1
self.serial_receiver
.recv()
.await
.expect("Unable to receive message from channel")
.contains(response);
.contains(response)
}

while let Ok(resp) = self.transceiver.1.try_recv() {
has_response = has_response || resp.contains(response);
// Consume all responses from serial port, to ensure we'll get the correct corresponding
async fn flush_serial_input(&mut self) -> std::io::Result<()> {
while !self.serial_receiver.is_empty() {
let _ = self
.serial_receiver
.recv()
.await
.map_err(|error| Error::new(ErrorKind::BrokenPipe, error))?;
}
has_response
Ok(())
}

async fn send_and_await_gcode(
Expand All @@ -150,6 +118,7 @@ impl Gcode {
expect: String,
timeout_seconds: usize,
) -> std::io::Result<()> {
self.flush_serial_input().await?;
self.send_gcode(code).await?;
self.await_response(expect, timeout_seconds).await?;
Ok(())
Expand Down Expand Up @@ -189,15 +158,7 @@ impl Gcode {

#[async_trait]
impl HardwareControl for Gcode {
async fn initialize(&mut self) {
// Run the serial port listener task
tokio::spawn(Gcode::run_listener(
self.serial_port
.try_clone_native()
.expect("Unable to clone serial connection"),
self.transceiver.0.clone(),
));
}
async fn initialize(&mut self) {}

async fn is_ready(&mut self) -> bool {
self.send_and_check_gcode(
Expand Down
10 changes: 10 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
pub mod api;
pub mod api_objects;
pub mod configuration;
pub mod display;
pub mod gcode;
pub mod printer;
pub mod printfile;
pub mod serial_handler;
pub mod sl1;
mod wrapped_framebuffer;
Loading