diff --git a/examples/rayon_demo/mandelbrot.a2l b/examples/rayon_demo/mandelbrot.a2l index abe32b4..066a3ef 100644 --- a/examples/rayon_demo/mandelbrot.a2l +++ b/examples/rayon_demo/mandelbrot.a2l @@ -66,7 +66,7 @@ /end MEMORY_SEGMENT /begin MEMORY_SEGMENT - mandelbrot "" DATA FLASH INTERN 0x80010000 32 -1 -1 -1 -1 -1 + mandelbrot "" DATA FLASH INTERN 0x80010000 24 -1 -1 -1 -1 -1 /begin IF_DATA XCP /begin SEGMENT /* index: */ 1 /* pages: */ 2 /* ext: */ 0 0 0 /begin CHECKSUM XCP_ADD_44 MAX_BLOCK_SIZE 0xFFFF EXTERNAL_FUNCTION "" /end CHECKSUM @@ -130,21 +130,17 @@ /end DAQ -/begin XCP_ON_UDP_IP 0x104 5555 ADDRESS "192.168.0.83" /end XCP_ON_UDP_IP +/begin XCP_ON_UDP_IP 0x104 5555 ADDRESS "127.0.0.1" /end XCP_ON_UDP_IP /end IF_DATA /begin CHARACTERISTIC Mandelbrot.width "" VALUE 0x80010010 F64 0 NO_COMPU_METHOD -1000000000000 1000000000000 /end CHARACTERISTIC /begin CHARACTERISTIC Mandelbrot.x "" VALUE 0x80010000 F64 0 NO_COMPU_METHOD -1000000000000 1000000000000 /end CHARACTERISTIC -/begin CHARACTERISTIC Mandelbrot.x_pixels "" VALUE 0x80010018 U32 0 NO_COMPU_METHOD 0 4294967295 /end CHARACTERISTIC /begin CHARACTERISTIC Mandelbrot.y "" VALUE 0x80010008 F64 0 NO_COMPU_METHOD -1000000000000 1000000000000 /end CHARACTERISTIC -/begin CHARACTERISTIC Mandelbrot.y_pixels "" VALUE 0x8001001C U32 0 NO_COMPU_METHOD 0 4294967295 /end CHARACTERISTIC /begin GROUP mandelbrot "" /begin REF_CHARACTERISTIC Mandelbrot.width Mandelbrot.x -Mandelbrot.x_pixels Mandelbrot.y -Mandelbrot.y_pixels /end REF_CHARACTERISTIC /end GROUP /begin COMPU_METHOD elapsed_time.Conv "" LINEAR "%6.3" "s" COEFFS_LINEAR 1 0 /end COMPU_METHOD diff --git a/examples/rayon_demo/mandelbrot.png b/examples/rayon_demo/mandelbrot.png index 529ed9a..85c3043 100644 Binary files a/examples/rayon_demo/mandelbrot.png and b/examples/rayon_demo/mandelbrot.png differ diff --git a/examples/rayon_demo/src/main.rs b/examples/rayon_demo/src/main.rs index b16c45a..25ed41d 100644 --- a/examples/rayon_demo/src/main.rs +++ b/examples/rayon_demo/src/main.rs @@ -8,30 +8,51 @@ use log::{debug, error, info, trace, warn}; use image::{ImageBuffer, Rgb}; use num::Complex; use rayon::prelude::*; -//use std::usize; use std::{thread, time::Duration}; use serde::{Deserialize, Serialize}; use xcp::*; use xcp_type_description_derive::XcpTypeDescription; -/// Write the buffer `pixels`, whose dimensions are given by `bounds`, to the -/// file named `filename`. -fn write_image( - filename: &str, - pixels: &[u8], - mandelbrot: CalSeg, -) -> Result<(), std::io::Error> { +const X_RES: usize = 3000; +const Y_RES: usize = 2000; + +#[derive(Debug, Copy, Clone, Serialize, Deserialize, XcpTypeDescription)] +struct Mandelbrot { + x: f64, + y: f64, + width: f64, +} + +// const MANDELBROT: Mandelbrot = Mandelbrot { +// x: -1.06, +// y: 0.271, +// width: 0.023, +// }; + +// Complete set +const MANDELBROT: Mandelbrot = Mandelbrot { + x: -0.5, + y: 0.0, + width: 3.0, +}; + +//--------------------------------------------------------------------------------------- +// Image rendering + +/// Write the buffer `pixels`, whose dimensions are given by `bounds`, to the file named `filename`. +fn write_image(filename: &str, pixels: &[u8]) -> Result<(), std::io::Error> { // Black and white // let output = File::create(filename)?; // let encoder = PNGEncoder::new(output); // encoder.encode( // &pixels, - // mandelbrot.x_pixels as u32, - // mandelbrot.y_pixels as u32, + // X_RES as u32, + // Y_RES as u32, // ColorType::Gray(8), // )?; + // Rainbox color map (credits to CoPilot) let mut color_map = Vec::with_capacity(256); for i in 0..256 { let (r, g, b) = match i { @@ -49,10 +70,9 @@ fn write_image( } // Color - let mut imgbuf = ImageBuffer::new(mandelbrot.x_pixels as u32, mandelbrot.y_pixels as u32); + let mut imgbuf = ImageBuffer::new(X_RES as u32, Y_RES as u32); for (x, y, rgb_pixel) in imgbuf.enumerate_pixels_mut() { - *rgb_pixel = - color_map[pixels[y as usize * mandelbrot.x_pixels as usize + x as usize] as usize]; + *rgb_pixel = color_map[pixels[y as usize * X_RES as usize + x as usize] as usize]; } imgbuf.save(filename).unwrap(); @@ -62,23 +82,6 @@ fn write_image( //--------------------------------------------------------------------------------------- // Mandelbrot set -#[derive(Debug, Copy, Clone, Serialize, Deserialize, XcpTypeDescription)] -struct Mandelbrot { - x_pixels: u32, - y_pixels: u32, - x: f64, - y: f64, - width: f64, -} - -const MANDELBROT: Mandelbrot = Mandelbrot { - x_pixels: 3000, - y_pixels: 2000, - x: -1.06, - y: 0.271, - width: 0.022, -}; - /// Try to determine if `c` is in the Mandelbrot set, using at most `limit` /// iterations to decide. /// @@ -107,7 +110,6 @@ fn escape_time(c: Complex, limit: usize) -> Option { /// The `upper_left` and `lower_right` parameters are points on the complex /// plane designating the area our image covers. fn pixel_to_point( - bounds: (usize, usize), pixel: (usize, usize), upper_left: Complex, lower_right: Complex, @@ -117,9 +119,8 @@ fn pixel_to_point( upper_left.im - lower_right.im, ); Complex { - re: upper_left.re + pixel.0 as f64 * width / bounds.0 as f64, - im: upper_left.im - pixel.1 as f64 * height / bounds.1 as f64, // Why subtraction here? pixel.1 increases as we go down, - // but the imaginary component increases as we go up. + re: upper_left.re + pixel.0 as f64 * width / X_RES as f64, + im: upper_left.im - pixel.1 as f64 * height / Y_RES as f64, } } @@ -140,7 +141,7 @@ fn render( // Render line for column in 0..length { - let point = pixel_to_point((length, 1), (column, row), upper_left, lower_right); + let point = pixel_to_point((column, row), upper_left, lower_right); pixels[column] = match escape_time(point, 255) { None => 0, Some(count) => 255 - count as u8, @@ -161,7 +162,7 @@ fn main() { .filter_level(log::LevelFilter::Info) .init(); - const BIND_ADDR: [u8; 4] = [192, 168, 0, 83]; // [127, 0, 0, 1] + const BIND_ADDR: [u8; 4] = [127, 0, 0, 1]; // [192, 168, 0, 83]; // [127, 0, 0, 1]; XcpBuilder::new("mandelbrot") .set_log_level(XcpLogLevel::Info) .enable_a2l(true) @@ -171,6 +172,10 @@ fn main() { let mandelbrot = Xcp::create_calseg("mandelbrot", &MANDELBROT, true); + // The pixel array on stack would overflow the addr offset + // let mut pixels: [u8; X_RES * Y_RES] = [0; X_RES * Y_RES]; + let mut pixels = vec![0; X_RES * Y_RES]; + // Create event for this worker thread and register variable index, which is the upper left corner of the rectangle let event = daq_create_event!("mainloop"); let mut elapsed_time: f64 = 0.0; @@ -182,40 +187,33 @@ fn main() { thread::sleep(Duration::from_micros(1000)); let start_time = std::time::Instant::now(); - let x_pixels: usize = mandelbrot.x_pixels as usize; - let y_pixels: usize = mandelbrot.y_pixels as usize; let lower_right = Complex { - re: mandelbrot.x - mandelbrot.width / 2.0, - im: mandelbrot.y - mandelbrot.width / 2.0 * y_pixels as f64 / x_pixels as f64, + re: mandelbrot.x + mandelbrot.width / 2.0, + im: mandelbrot.y - mandelbrot.width / 2.0 * Y_RES as f64 / X_RES as f64, }; let upper_left = Complex { - re: mandelbrot.x + mandelbrot.width / 2.0, - im: mandelbrot.y + mandelbrot.width / 2.0 * y_pixels as f64 / x_pixels as f64, + re: mandelbrot.x - mandelbrot.width / 2.0, + im: mandelbrot.y + mandelbrot.width / 2.0 * Y_RES as f64 / X_RES as f64, }; - // Calculate image by lines in parallel - let mut pixels = vec![0; x_pixels * y_pixels]; - let lines: Vec<(usize, &mut [u8])> = pixels.chunks_mut(x_pixels).enumerate().collect(); + // Calculate image lines in parallel + let lines: Vec<(usize, &mut [u8])> = pixels.chunks_mut(X_RES).enumerate().collect(); lines.into_par_iter().for_each(|(y, band)| { - let band_upper_left = - pixel_to_point((x_pixels, y_pixels), (0, y), upper_left, lower_right); - let band_lower_right = pixel_to_point( - (x_pixels, y_pixels), - (x_pixels, y + 1), - upper_left, - lower_right, - ); - render(band, y, x_pixels, band_upper_left, band_lower_right); + let band_upper_left = pixel_to_point((0, y), upper_left, lower_right); + let band_lower_right = pixel_to_point((X_RES, y + 1), upper_left, lower_right); + render(band, y, X_RES, band_upper_left, band_lower_right); }); - // Measure runtime + // Measure run time elapsed_time = start_time.elapsed().as_secs_f64(); event.trigger(); println!("Image rendered, duration = {:.3} s", elapsed_time); + // Measure the pixel array from heap, with an individual event + //daq_event!(pixels, "pixels"); + // Render image to png - let m = mandelbrot.clone(); - write_image("mandelbrot.png", &pixels, m).expect("error writing PNG file"); + write_image("mandelbrot.png", &pixels).expect("error writing PNG file"); println!("Image written to mandelbrot.png"); // Write A2L file diff --git a/xcp_client/src/xcp_client.rs b/xcp_client/src/xcp_client.rs index 2ea9245..98d3f38 100644 --- a/xcp_client/src/xcp_client.rs +++ b/xcp_client/src/xcp_client.rs @@ -651,7 +651,9 @@ impl XcpClient { } } None => { - panic!("xcp_command: bug in receive_task, no data in channel") + // @@@@ Empty response, channel has been closed, return with XcpError Timeout + error!("xcp_command: receive_task channel closed"); + Err(Box::new(XcpError::new(ERROR_CMD_TIMEOUT)) as Box) } } }