Created
June 24, 2024 20:59
-
-
Save bczhc/0e02f9ebf96a207f9d1274f7fc567895 to your computer and use it in GitHub Desktop.
宿舍墨水屏 用到的一些代码
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/env ruby | |
require 'json' | |
require 'cgi' | |
require 'shellwords' | |
exports = JSON.parse(File.read('/home/bczhc/exports.json')) | |
response = `curl https://api.coincap.io/v2/rates/bitcoin -s` | |
btc_price = JSON.parse(response)['data']['rateUsd'].to_f | |
params = { | |
electricity: exports['electricity'], | |
toZeroDate: Time.at(exports['toZeroAt']).strftime('%d %b %H:%M:%S'), | |
btcPrice: btc_price, | |
updateAt: Time.now.strftime('%d %b %H:%M:%S'), | |
} | |
puts params | |
params_url_encoded = CGI.escape params.to_json | |
image_url= "http://192.168.4.1:8081/?name=eink-screen¶ms=#{params_url_encoded}" | |
puts image_url | |
`curl #{Shellwords.escape(image_url)} -s > eink.png` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::io::{Read, Write}; | |
use std::net::{SocketAddr, TcpStream}; | |
use std::path::PathBuf; | |
use clap::Parser; | |
use image::GenericImageView; | |
use rand::rngs::OsRng; | |
use rand::RngCore; | |
/// ## Coordinate | |
/// [Width] | |
/// ----------- | |
/// | | | |
/// | | | |
/// | | [Height] | |
/// | | | |
/// | | | |
/// | | | |
/// ----------- | |
/// |||| | |
/// Pins | |
/// | |
/// The top-left point is (0, 0), and the bottom-right one is (width, height). | |
/// | |
struct ScreenBuffer { | |
width: usize, | |
height: usize, | |
buffer: Vec<u8>, | |
} | |
impl ScreenBuffer { | |
fn new(width: usize, height: usize) -> Self { | |
if (width * height) % 8 != 0 { | |
panic!("(width * height) must be a multiple of 8"); | |
} | |
Self { | |
width, | |
height, | |
buffer: vec![0xff; width * height / 8], | |
} | |
} | |
fn pixel_bit(black: bool) -> bool { | |
!black | |
} | |
fn set_pixel(&mut self, x: usize, y: usize, black: bool) { | |
assert!(x < EPD_2IN13D_WIDTH && y < EPD_2IN13D_HEIGHT); | |
let bits_offset = self.width * y + x; | |
let (byte_n, byte_bit_n) = (bits_offset / 8, (bits_offset % 8) as u32); | |
self.buffer[byte_n] = n_bit_set(self.buffer[byte_n], byte_bit_n, Self::pixel_bit(black)); | |
} | |
fn set_pixel_n(&mut self, pixel_n: usize, black: bool) { | |
assert!(pixel_n < self.width * self.height); | |
let (byte_n, byte_bit_n) = (pixel_n / 8, (pixel_n % 8) as u32); | |
self.buffer[byte_n] = n_bit_set(self.buffer[byte_n], byte_bit_n, Self::pixel_bit(black)); | |
} | |
fn get_pixel(&mut self, x: usize, y: usize) -> bool { | |
assert!(x < EPD_2IN13D_WIDTH && y < EPD_2IN13D_HEIGHT); | |
let bits_offset = self.width * y + x; | |
let (byte_n, byte_bit_n) = (bits_offset / 8, (bits_offset % 8) as u32); | |
n_bit(self.buffer[byte_n], byte_bit_n) | |
} | |
} | |
#[derive(Debug, clap::Parser)] | |
struct Args { | |
image: PathBuf, | |
} | |
fn main() -> anyhow::Result<()> { | |
let args = Args::parse(); | |
let mut buffer = ScreenBuffer::new(EPD_2IN13D_WIDTH, EPD_2IN13D_HEIGHT); | |
let image_path = args.image; | |
let image = image::open(image_path)?; | |
let (image_w, image_h) = image.dimensions(); | |
if image_w as usize != EPD_2IN13D_HEIGHT || image_h as usize != EPD_2IN13D_WIDTH { | |
panic!( | |
"Wrong image specification: width and height must be {} and {}", | |
EPD_2IN13D_HEIGHT, EPD_2IN13D_WIDTH | |
); | |
} | |
let mut pixel_n = 0; | |
for x in 0..image_w { | |
for y in (0..image_h).rev() { | |
let pixel = image.get_pixel(x, y); | |
let black = pixel.0[..3] == [0x00, 0x00, 0x00]; | |
buffer.set_pixel_n(pixel_n, black); | |
pixel_n += 1; | |
} | |
} | |
update_screen(&buffer.buffer)?; | |
Ok(()) | |
} | |
/// `n` is counted from the MSB (left-to-right), and starts from zero. | |
fn n_bit_set(mut b: u8, n: u32, is_one: bool) -> u8 { | |
((b.rotate_left(n + 1) & 0b11111110) | u8::from(is_one)).rotate_right(n + 1) | |
} | |
/// `n` is counted from the MSB (left-to-right), and starts from zero. | |
fn n_bit(b: u8, n: u32) -> bool { | |
b.rotate_left(n + 1) % 2 == 1 | |
} | |
fn update_screen(image: &[u8]) -> anyhow::Result<()> { | |
let mut stream = TcpStream::connect("192.168.4.12:5002".parse::<SocketAddr>().unwrap())?; | |
stream.write_all(&build_directive_string("update"))?; | |
stream.write_all(image)?; | |
let mut response = String::new(); | |
stream.read_to_string(&mut response)?; | |
println!("{}", response); | |
Ok(()) | |
} | |
fn build_directive_string(d: &str) -> [u8; 16] { | |
let mut buf = [0_u8; 16]; | |
buf[..d.len()].copy_from_slice(d.as_bytes()); | |
buf | |
} | |
pub const EPD_2IN13D_WIDTH: usize = 104; | |
pub const EPD_2IN13D_HEIGHT: usize = 212; | |
fn checkerboard_image_buffer() -> Vec<u8> { | |
let mut image_buffer = vec![0_u8; EPD_2IN13D_WIDTH / 8 * EPD_2IN13D_HEIGHT]; | |
let row_bytes = EPD_2IN13D_WIDTH / 8; | |
for i in 0..EPD_2IN13D_HEIGHT { | |
let byte_filled = match i % 2 { | |
0 => 0b01010101_u8, | |
1 => 0b10101010_u8, | |
_ => unreachable!(), | |
}; | |
image_buffer[(row_bytes * i)..(row_bytes * i + row_bytes)].fill(byte_filled); | |
} | |
image_buffer | |
} | |
fn new_white_image_buffer() -> Vec<u8> { | |
let mut buf = vec![0_u8; EPD_2IN13D_WIDTH / 8 * EPD_2IN13D_HEIGHT]; | |
buf.fill(0xff); | |
buf | |
} | |
fn random_pattern() -> Vec<u8> { | |
let mut image_buffer = vec![0_u8; EPD_2IN13D_WIDTH / 8 * EPD_2IN13D_HEIGHT]; | |
OsRng.fill_bytes(&mut image_buffer); | |
image_buffer | |
} | |
#[cfg(test)] | |
mod test { | |
use crate::{n_bit, n_bit_set}; | |
#[test] | |
#[allow(clippy::bool_assert_comparison)] | |
fn bits() { | |
assert_eq!(n_bit(0b10101010, 0), true); | |
assert_eq!(n_bit(0b10101010, 1), false); | |
assert_eq!(n_bit(0b10101010, 2), true); | |
assert_eq!(n_bit(0b10101010, 3), false); | |
assert_eq!(n_bit(0b10101010, 4), true); | |
assert_eq!(n_bit(0b10101010, 5), false); | |
assert_eq!(n_bit(0b10101010, 6), true); | |
assert_eq!(n_bit(0b10101010, 7), false); | |
assert_eq!(n_bit_set(0b10000110, 3, true), 0b10010110); | |
assert_eq!(n_bit_set(0b10000110, 0, false), 0b00000110); | |
assert_eq!(n_bit_set(0b10101101, 3, true), 0b10111101); | |
assert_eq!(n_bit_set(0b01101001, 6, false), 0b01101001); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment