diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..0bedb69 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,106 @@ +target_steps: &target_steps + docker: + - image: circleci/rust:1.42.0 + steps: + - checkout + - restore_cache: + key: v1-sh1106-{{ .Environment.CIRCLE_JOB }}-{{ checksum "Cargo.toml" }} + - run: sudo apt install -qq linkchecker + - run: rustup default ${RUST_VERSION:-stable} + - run: rustup component add rustfmt + - run: | + SYSROOT=$(rustc --print sysroot) + + if [[ ! "$SYSROOT" =~ "$TARGET" ]]; then + rustup target add $TARGET + else + echo "Target $TARGET is already installed" + fi + - run: ./build.sh + - save_cache: + key: v1-sh1106-{{ .Environment.CIRCLE_JOB }}-{{ checksum "Cargo.toml" }} + paths: + - ./target + - /home/ubuntu/.cargo + +version: 2 +jobs: + target-arm-unknown-linux-eabi: + environment: + - TARGET: 'arm-unknown-linux-gnueabi' + - DISABLE_EXAMPLES: 1 + <<: *target_steps + + target-armv7-unknown-linux-gnueabihf: + environment: + - TARGET: 'armv7-unknown-linux-gnueabihf' + - DISABLE_EXAMPLES: 1 + <<: *target_steps + + target-x86_64-unknown-linux-gnu: + environment: + - TARGET: 'x86_64-unknown-linux-gnu' + - DISABLE_EXAMPLES: 1 + <<: *target_steps + + target-x86_64-unknown-linux-musl: + environment: + - TARGET: 'x86_64-unknown-linux-musl' + - DISABLE_EXAMPLES: 1 + <<: *target_steps + + target-thumbv6m-none-eabi: + environment: + - TARGET: 'thumbv6m-none-eabi' + # Disable example builds as they target thumbv7 and up + - DISABLE_EXAMPLES: 1 + <<: *target_steps + + target-thumbv7em-none-eabi: + environment: + - TARGET: 'thumbv7em-none-eabi' + <<: *target_steps + + target-thumbv7em-none-eabihf: + environment: + - TARGET: 'thumbv7em-none-eabihf' + <<: *target_steps + + target-thumbv7m-none-eabi: + environment: + - TARGET: 'thumbv7m-none-eabi' + <<: *target_steps + +build_jobs: &build_jobs + jobs: + # Raspberry Pi 1 + - target-arm-unknown-linux-eabi + + # Raspberry Pi 2, 3, etc + - target-armv7-unknown-linux-gnueabihf + + # Linux + - target-x86_64-unknown-linux-gnu + - target-x86_64-unknown-linux-musl + + # Bare metal + - target-thumbv6m-none-eabi + - target-thumbv7em-none-eabi + - target-thumbv7em-none-eabihf + - target-thumbv7m-none-eabi + +workflows: + version: 2 + build_all: + <<: *build_jobs + + # Build every day + nightly: + <<: *build_jobs + triggers: + - schedule: + cron: '0 0 * * *' + filters: + branches: + only: + - master diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f3a417c..0000000 --- a/.travis.yml +++ /dev/null @@ -1,71 +0,0 @@ -# Based on the "trust" template v0.1.2 -# https://github.com/japaric/trust/tree/v0.1.2 - -dist: trusty -language: rust -rust: - - stable - - beta - - nightly -sudo: required - -matrix: - include: - # Raspberry Pi 1 - - env: TARGET=arm-unknown-linux-gnueabi DISABLE_EXAMPLES=1 - - # Raspberry Pi 2, 3, etc - - env: TARGET=armv7-unknown-linux-gnueabihf DISABLE_EXAMPLES=1 - - env: TARGET=x86_64-unknown-linux-gnu DISABLE_EXAMPLES=1 - - env: TARGET=x86_64-unknown-linux-musl DISABLE_EXAMPLES=1 - - # Bare metal - - env: TARGET=thumbv6m-none-eabi DISABLE_EXAMPLES=1 - - env: TARGET=thumbv7em-none-eabi - - env: TARGET=thumbv7em-none-eabihf - - env: TARGET=thumbv7m-none-eabi - - - rust: nightly - env: TARGET=thumbv7m-none-eabi - - - rust: beta - env: TARGET=thumbv7m-none-eabi - - # Always supply a target - exclude: - - rust: stable - - rust: beta - - rust: nightly - -before_install: - - rustup self update - - rustup update - - rustup component add rustfmt - - pip install linkchecker --user - -install: - - | - SYSROOT=$(rustc --print sysroot) - - if [[ ! "$SYSROOT" =~ "$TARGET" ]]; then - rustup target add $TARGET - else - echo "Target $TARGET is already installed" - fi - -script: - - cargo fmt --all -- --check - - ./build.sh - -after_success: - - cargo doc - - linkchecker target/doc/sh1106 - -cache: cargo -before_cache: - # Travis can't cache files that are not readable by "others" - - chmod -R a+r $HOME/.cargo - -notifications: - email: - on_success: never diff --git a/CHANGELOG.md b/CHANGELOG.md index c9d7258..46e479e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,22 @@ # Changelog -`sh1106` is a Rust driver for the SH1106 OLED display. It supports +[`sh1106`](https://crates.io/crates/sh1106) is a Rust driver for the SH1106 OLED display. It supports [embedded-graphics](https://crates.io/crates/embedded-graphics) or raw pixel drawing modes and works with the [embedded-hal](crates.io/crates/embedded-hal) traits for maximum portability. -## 0.3.0-alpha.4 + + +## [Unreleased] - ReleaseDate + +### Added + +- Migrate from Travis to CircleCI + +### Changed + +- **(breaking)** [#18](https://github.com/jamwaffles/sh1106/pull/18) Upgrade to embedded-graphics 0.6.0 + +## [0.3.0-alpha.4] ### Fixed @@ -30,54 +42,20 @@ let mut disp: GraphicsMode<_> = sh1106::Builder::new() Upgrade to new embedded-graphics `0.6.0-alpha.2` release. Please see the [embedded-graphics changelog](https://github.com/jamwaffles/embedded-graphics/blob/c0ed1700635f307a4c5114fec1769147878fd584/CHANGELOG.md) for more information. -### Added - -- None - ### Changed - **(breaking)** #11 Upgraded to [embedded-graphics](https://crates.io/crates/embedded-graphics) 0.6.0-alpha.2 -### Deprecated - -- None - -### Removed - -- None - -### Fixed - -- None - -### Security - -- None - ## 0.3.0-alpha.1 Upgrade to new embedded-graphics `0.6.0-alpha.1` release. Please see the [embedded-graphics changelog](https://github.com/jamwaffles/embedded-graphics/blob/embedded-graphics-v0.6.0-alpha.1/CHANGELOG.md) for more information. -### Added - -- None - ### Changed - **(breaking)** #9 Upgraded to [embedded-graphics](https://crates.io/crates/embedded-graphics) 0.6.0-alpha.1 -### Deprecated - -- None - -### Removed - -- None - -### Fixed - -- None - -### Security + -- None +[unreleased]: https://github.com/jamwaffles/sh1106/compare/v0.3.0-alpha.4...HEAD +[0.3.0-alpha.4]: https://github.com/jamwaffles/sh1106/compare/v0.3.0-alpha.3...v0.3.0-alpha.4 +[0.3.0-alpha.3]: https://github.com/jamwaffles/sh1106/compare/v0.3.0-alpha.2...v0.3.0-alpha.3 diff --git a/Cargo.toml b/Cargo.toml index 402eb4b..37c04e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,16 +11,19 @@ readme = "README.md" repository = "https://github.com/jamwaffles/sh1106" version = "0.3.0-alpha.4" edition = "2018" -[badges.travis-ci] -branch = "master" -repository = "jamwaffles/sh1106" + +[package.metadata.docs.rs] +default-target = "x86_64-unknown-linux-gnu" + +[badges] +circle-ci = { repository = "jamwaffles/sh1106", branch = "master" } [dependencies] embedded-hal = "0.2.3" [dependencies.embedded-graphics] optional = true -version = "=0.6.0-alpha.2" +version = "0.6.0" [dev-dependencies] cortex-m = "0.6.0" diff --git a/README.md b/README.md index 5f0ec3a..661b334 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ # SH1106 driver -[![Build Status](https://travis-ci.org/jamwaffles/sh1106.svg?branch=master)](https://travis-ci.org/jamwaffles/sh1106) +[![Build Status](https://circleci.com/gh/jamwaffles/sh1106/tree/master.svg?style=shield)](https://circleci.com/gh/jamwaffles/sh1106/tree/master) +[![Crates.io](https://img.shields.io/crates/v/sh1106.svg)](https://crates.io/crates/sh1106) +[![Docs.rs](https://docs.rs/sh1106/badge.svg)](https://docs.rs/sh1106) -[![SH116 display module showing the Rust logo](readme_banner.jpg?raw=true)](examples/image.rs) +[![SH1106 display module showing the Rust logo](readme_banner.jpg?raw=true)](examples/image.rs) I2C driver for the SH1106 OLED display written in 100% Rust @@ -11,28 +13,80 @@ I2C driver for the SH1106 OLED display written in 100% Rust From [`examples/text.rs`](examples/text.rs): ```rust -// ...snip, see examples/text.rs for runnable code ... - -let i2c = /* ... */; - -let mut disp: GraphicsMode<_> = Builder::new().connect_i2c(i2c).into(); - -disp.init().unwrap(); -disp.flush().unwrap(); - -disp.draw( - Font6x8::render_str("Hello world!") - .stroke_width(1) - .into_iter(), -); -disp.draw( - Font6x8::render_str("Hello Rust!") - .stroke_width(1) - .translate(Point::new(0, 16)) - .into_iter(), -); - -disp.flush().unwrap(); +#![no_std] +#![no_main] + +use cortex_m_rt::{entry, exception, ExceptionFrame}; +use embedded_graphics::{ + fonts::{Font6x8, Text}, + pixelcolor::BinaryColor, + prelude::*, + style::TextStyle, +}; +use panic_semihosting as _; +use sh1106::{prelude::*, Builder}; +use stm32f1xx_hal::{ + i2c::{BlockingI2c, DutyCycle, Mode}, + prelude::*, + stm32, +}; + +#[entry] +fn main() -> ! { + let dp = stm32::Peripherals::take().unwrap(); + + let mut flash = dp.FLASH.constrain(); + let mut rcc = dp.RCC.constrain(); + + let clocks = rcc.cfgr.freeze(&mut flash.acr); + + let mut afio = dp.AFIO.constrain(&mut rcc.apb2); + + let mut gpiob = dp.GPIOB.split(&mut rcc.apb2); + + let scl = gpiob.pb8.into_alternate_open_drain(&mut gpiob.crh); + let sda = gpiob.pb9.into_alternate_open_drain(&mut gpiob.crh); + + let i2c = BlockingI2c::i2c1( + dp.I2C1, + (scl, sda), + &mut afio.mapr, + Mode::Fast { + frequency: 400_000, + duty_cycle: DutyCycle::Ratio2to1, + }, + clocks, + &mut rcc.apb1, + 1000, + 10, + 1000, + 1000, + ); + + let mut disp: GraphicsMode<_> = Builder::new().connect_i2c(i2c).into(); + + disp.init().unwrap(); + disp.flush().unwrap(); + + Text::new("Hello world!", Point::zero()) + .into_styled(TextStyle::new(Font6x8, BinaryColor::On)) + .draw(&mut disp) + .unwrap(); + + Text::new("Hello Rust!", Point::new(0, 16)) + .into_styled(TextStyle::new(Font6x8, BinaryColor::On)) + .draw(&mut disp) + .unwrap(); + + disp.flush().unwrap(); + + loop {} +} + +#[exception] +fn HardFault(ef: &ExceptionFrame) -> ! { + panic!("{:#?}", ef); +} ``` ## License diff --git a/build.rs b/build.rs index 34363d2..364f9a0 100644 --- a/build.rs +++ b/build.rs @@ -1,7 +1,4 @@ -use std::env; -use std::fs::File; -use std::io::Write; -use std::path::PathBuf; +use std::{env, fs::File, io::Write, path::PathBuf}; pub fn main() { // Put the linker script somewhere the linker can find it diff --git a/examples/graphics.rs b/examples/graphics.rs index aa1d2b9..4d970ce 100644 --- a/examples/graphics.rs +++ b/examples/graphics.rs @@ -17,21 +17,20 @@ #![no_std] #![no_main] -extern crate cortex_m; -extern crate cortex_m_rt as rt; -extern crate panic_semihosting; -extern crate stm32f1xx_hal as hal; - -use cortex_m_rt::ExceptionFrame; -use cortex_m_rt::{entry, exception}; -use embedded_graphics::pixelcolor::BinaryColor; -use embedded_graphics::prelude::*; -use embedded_graphics::primitives::{Circle, Line, Rectangle}; -use hal::i2c::{BlockingI2c, DutyCycle, Mode}; -use hal::prelude::*; -use hal::stm32; -use sh1106::prelude::*; -use sh1106::Builder; +use cortex_m_rt::{entry, exception, ExceptionFrame}; +use embedded_graphics::{ + pixelcolor::BinaryColor, + prelude::*, + primitives::{Circle, Line, Rectangle}, + style::PrimitiveStyle, +}; +use panic_semihosting as _; +use sh1106::{prelude::*, Builder}; +use stm32f1xx_hal::{ + i2c::{BlockingI2c, DutyCycle, Mode}, + prelude::*, + stm32, +}; #[entry] fn main() -> ! { @@ -70,33 +69,30 @@ fn main() -> ! { disp.init().unwrap(); disp.flush().unwrap(); - disp.draw( - Line::new(Point::new(8, 16 + 16), Point::new(8 + 16, 16 + 16)) - .stroke(Some(BinaryColor::On)) - .into_iter(), - ); - disp.draw( - Line::new(Point::new(8, 16 + 16), Point::new(8 + 8, 16)) - .stroke(Some(BinaryColor::On)) - .into_iter(), - ); - disp.draw( - Line::new(Point::new(8 + 16, 16 + 16), Point::new(8 + 8, 16)) - .stroke(Some(BinaryColor::On)) - .into_iter(), - ); - - disp.draw( - Rectangle::new(Point::new(48, 16), Point::new(48 + 16, 16 + 16)) - .stroke(Some(BinaryColor::On)) - .into_iter(), - ); - - disp.draw( - Circle::new(Point::new(96, 16 + 8), 8) - .stroke(Some(BinaryColor::On)) - .into_iter(), - ); + Line::new(Point::new(8, 16 + 16), Point::new(8 + 16, 16 + 16)) + .into_styled(PrimitiveStyle::with_stroke(BinaryColor::On, 1)) + .draw(&mut disp) + .unwrap(); + + Line::new(Point::new(8, 16 + 16), Point::new(8 + 8, 16)) + .into_styled(PrimitiveStyle::with_stroke(BinaryColor::On, 1)) + .draw(&mut disp) + .unwrap(); + + Line::new(Point::new(8 + 16, 16 + 16), Point::new(8 + 8, 16)) + .into_styled(PrimitiveStyle::with_stroke(BinaryColor::On, 1)) + .draw(&mut disp) + .unwrap(); + + Rectangle::new(Point::new(48, 16), Point::new(48 + 16, 16 + 16)) + .into_styled(PrimitiveStyle::with_stroke(BinaryColor::On, 1)) + .draw(&mut disp) + .unwrap(); + + Circle::new(Point::new(96, 16 + 8), 8) + .into_styled(PrimitiveStyle::with_stroke(BinaryColor::On, 1)) + .draw(&mut disp) + .unwrap(); disp.flush().unwrap(); diff --git a/examples/graphics_128x32.rs b/examples/graphics_128x32.rs index 9bbd9ca..043812b 100644 --- a/examples/graphics_128x32.rs +++ b/examples/graphics_128x32.rs @@ -7,21 +7,20 @@ #![no_std] #![no_main] -extern crate cortex_m; -extern crate cortex_m_rt as rt; -extern crate panic_semihosting; -extern crate stm32f1xx_hal as hal; - -use cortex_m_rt::ExceptionFrame; -use cortex_m_rt::{entry, exception}; -use embedded_graphics::pixelcolor::BinaryColor; -use embedded_graphics::prelude::*; -use embedded_graphics::primitives::{Circle, Line, Rectangle}; -use hal::i2c::{BlockingI2c, DutyCycle, Mode}; -use hal::prelude::*; -use hal::stm32; -use sh1106::prelude::*; -use sh1106::Builder; +use cortex_m_rt::{entry, exception, ExceptionFrame}; +use embedded_graphics::{ + pixelcolor::BinaryColor, + prelude::*, + primitives::{Circle, Line, Rectangle}, + style::PrimitiveStyle, +}; +use panic_semihosting as _; +use sh1106::{prelude::*, Builder}; +use stm32f1xx_hal::{ + i2c::{BlockingI2c, DutyCycle, Mode}, + prelude::*, + stm32, +}; #[entry] fn main() -> ! { @@ -64,36 +63,33 @@ fn main() -> ! { let yoffset = 8; - disp.draw( - Line::new( - Point::new(8, 16 + yoffset), - Point::new(8 + 16, 16 + yoffset), - ) - .stroke(Some(BinaryColor::On)) - .into_iter(), - ); - disp.draw( - Line::new(Point::new(8, 16 + yoffset), Point::new(8 + 8, yoffset)) - .stroke(Some(BinaryColor::On)) - .into_iter(), - ); - disp.draw( - Line::new(Point::new(8 + 16, 16 + yoffset), Point::new(8 + 8, yoffset)) - .stroke(Some(BinaryColor::On)) - .into_iter(), - ); - - disp.draw( - Rectangle::new(Point::new(48, yoffset), Point::new(48 + 16, 16 + yoffset)) - .stroke(Some(BinaryColor::On)) - .into_iter(), - ); - - disp.draw( - Circle::new(Point::new(96, yoffset + 8), 8) - .stroke(Some(BinaryColor::On)) - .into_iter(), - ); + Line::new( + Point::new(8, 16 + yoffset), + Point::new(8 + 16, 16 + yoffset), + ) + .into_styled(PrimitiveStyle::with_stroke(BinaryColor::On, 1)) + .draw(&mut disp) + .unwrap(); + + Line::new(Point::new(8, 16 + yoffset), Point::new(8 + 8, yoffset)) + .into_styled(PrimitiveStyle::with_stroke(BinaryColor::On, 1)) + .draw(&mut disp) + .unwrap(); + + Line::new(Point::new(8 + 16, 16 + yoffset), Point::new(8 + 8, yoffset)) + .into_styled(PrimitiveStyle::with_stroke(BinaryColor::On, 1)) + .draw(&mut disp) + .unwrap(); + + Rectangle::new(Point::new(48, yoffset), Point::new(48 + 16, 16 + yoffset)) + .into_styled(PrimitiveStyle::with_stroke(BinaryColor::On, 1)) + .draw(&mut disp) + .unwrap(); + + Circle::new(Point::new(96, yoffset + 8), 8) + .into_styled(PrimitiveStyle::with_stroke(BinaryColor::On, 1)) + .draw(&mut disp) + .unwrap(); disp.flush().unwrap(); diff --git a/examples/image.rs b/examples/image.rs index ad1d81e..97de625 100644 --- a/examples/image.rs +++ b/examples/image.rs @@ -23,19 +23,19 @@ #![no_std] #![no_main] -extern crate cortex_m; -extern crate cortex_m_rt as rt; -extern crate panic_semihosting; -extern crate stm32f1xx_hal as hal; - -use cortex_m_rt::ExceptionFrame; -use cortex_m_rt::{entry, exception}; -use embedded_graphics::{image::Image, pixelcolor::BinaryColor, prelude::*}; -use hal::i2c::{BlockingI2c, DutyCycle, Mode}; -use hal::prelude::*; -use hal::stm32; -use sh1106::prelude::*; -use sh1106::Builder; +use cortex_m_rt::{entry, exception, ExceptionFrame}; +use embedded_graphics::{ + image::{Image, ImageRawLE}, + pixelcolor::BinaryColor, + prelude::*, +}; +use panic_semihosting as _; +use sh1106::{prelude::*, Builder}; +use stm32f1xx_hal::{ + i2c::{BlockingI2c, DutyCycle, Mode}, + prelude::*, + stm32, +}; #[entry] fn main() -> ! { @@ -74,10 +74,9 @@ fn main() -> ! { disp.init().unwrap(); disp.flush().unwrap(); - let im: Image = - Image::new(include_bytes!("./rust.raw"), 64, 64).translate(Point::new(32, 0)); + let im: ImageRawLE = ImageRawLE::new(include_bytes!("./rust.raw"), 64, 64); - disp.draw(im.into_iter()); + Image::new(&im, Point::new(32, 0)).draw(&mut disp).unwrap(); disp.flush().unwrap(); diff --git a/examples/image_spi.rs b/examples/image_spi.rs index 92fbec8..b0a4d28 100644 --- a/examples/image_spi.rs +++ b/examples/image_spi.rs @@ -25,20 +25,16 @@ #![no_std] #![no_main] -extern crate cortex_m; -extern crate cortex_m_rt as rt; -extern crate panic_semihosting; -extern crate stm32f1xx_hal as hal; - -use cortex_m_rt::ExceptionFrame; -use cortex_m_rt::{entry, exception}; -use embedded_graphics::{image::Image, pixelcolor::BinaryColor, prelude::*}; +use cortex_m_rt::{entry, exception, ExceptionFrame}; +use embedded_graphics::{ + image::{Image, ImageRawLE}, + pixelcolor::BinaryColor, + prelude::*, +}; use embedded_hal::spi; -use hal::prelude::*; -use hal::spi::Spi; -use hal::stm32; -use sh1106::prelude::*; -use sh1106::Builder; +use panic_semihosting as _; +use sh1106::{prelude::*, Builder}; +use stm32f1xx_hal::{prelude::*, spi::Spi, stm32}; #[entry] fn main() -> ! { @@ -79,10 +75,9 @@ fn main() -> ! { disp.init().unwrap(); disp.flush().unwrap(); - let im: Image = - Image::new(include_bytes!("./rust.raw"), 64, 64).translate(Point::new(32, 0)); + let im: ImageRawLE = ImageRawLE::new(include_bytes!("./rust.raw"), 64, 64); - disp.draw(im.into_iter()); + Image::new(&im, Point::new(32, 0)).draw(&mut disp).unwrap(); disp.flush().unwrap(); diff --git a/examples/pixelsquare.rs b/examples/pixelsquare.rs index 40559d1..242d445 100644 --- a/examples/pixelsquare.rs +++ b/examples/pixelsquare.rs @@ -23,18 +23,14 @@ #![no_std] #![no_main] -extern crate cortex_m; -extern crate cortex_m_rt as rt; -extern crate panic_semihosting; -extern crate stm32f1xx_hal as hal; - -use cortex_m_rt::ExceptionFrame; -use cortex_m_rt::{entry, exception}; -use hal::i2c::{BlockingI2c, DutyCycle, Mode}; -use hal::prelude::*; -use hal::stm32; -use sh1106::prelude::*; -use sh1106::Builder; +use cortex_m_rt::{entry, exception, ExceptionFrame}; +use panic_semihosting as _; +use sh1106::{prelude::*, Builder}; +use stm32f1xx_hal::{ + i2c::{BlockingI2c, DutyCycle, Mode}, + prelude::*, + stm32, +}; #[entry] fn main() -> ! { diff --git a/examples/rotation.rs b/examples/rotation.rs index 6d0d6aa..862fc3a 100644 --- a/examples/rotation.rs +++ b/examples/rotation.rs @@ -23,19 +23,19 @@ #![no_std] #![no_main] -extern crate cortex_m; -extern crate cortex_m_rt as rt; -extern crate panic_semihosting; -extern crate stm32f1xx_hal as hal; - -use cortex_m_rt::ExceptionFrame; -use cortex_m_rt::{entry, exception}; -use embedded_graphics::{image::Image, pixelcolor::BinaryColor, prelude::*}; -use hal::i2c::{BlockingI2c, DutyCycle, Mode}; -use hal::prelude::*; -use hal::stm32; -use sh1106::prelude::*; -use sh1106::Builder; +use cortex_m_rt::{entry, exception, ExceptionFrame}; +use embedded_graphics::{ + image::{Image, ImageRawLE}, + pixelcolor::BinaryColor, + prelude::*, +}; +use panic_semihosting as _; +use sh1106::{prelude::*, Builder}; +use stm32f1xx_hal::{ + i2c::{BlockingI2c, DutyCycle, Mode}, + prelude::*, + stm32, +}; #[entry] fn main() -> ! { @@ -84,10 +84,14 @@ fn main() -> ! { let (w, h) = disp.get_dimensions(); - let im: Image = Image::new(include_bytes!("./rust.raw"), 64, 64) - .translate(Point::new(w as i32 / 2 - 64 / 2, h as i32 / 2 - 64 / 2)); + let im: ImageRawLE = ImageRawLE::new(include_bytes!("./rust.raw"), 64, 64); - disp.draw(im.into_iter()); + Image::new( + &im, + Point::new(w as i32 / 2 - 64 / 2, h as i32 / 2 - 64 / 2), + ) + .draw(&mut disp) + .unwrap(); disp.flush().unwrap(); diff --git a/examples/text.rs b/examples/text.rs index a65c2c6..8111ab6 100644 --- a/examples/text.rs +++ b/examples/text.rs @@ -18,20 +18,20 @@ #![no_std] #![no_main] -extern crate cortex_m; -extern crate cortex_m_rt as rt; -extern crate panic_semihosting; -extern crate stm32f1xx_hal as hal; - -use cortex_m_rt::ExceptionFrame; -use cortex_m_rt::{entry, exception}; -use embedded_graphics::fonts::Font6x8; -use embedded_graphics::prelude::*; -use hal::i2c::{BlockingI2c, DutyCycle, Mode}; -use hal::prelude::*; -use hal::stm32; -use sh1106::prelude::*; -use sh1106::Builder; +use cortex_m_rt::{entry, exception, ExceptionFrame}; +use embedded_graphics::{ + fonts::{Font6x8, Text}, + pixelcolor::BinaryColor, + prelude::*, + style::TextStyle, +}; +use panic_semihosting as _; +use sh1106::{prelude::*, Builder}; +use stm32f1xx_hal::{ + i2c::{BlockingI2c, DutyCycle, Mode}, + prelude::*, + stm32, +}; #[entry] fn main() -> ! { @@ -70,17 +70,15 @@ fn main() -> ! { disp.init().unwrap(); disp.flush().unwrap(); - disp.draw( - Font6x8::render_str("Hello world!") - .stroke_width(1) - .into_iter(), - ); - disp.draw( - Font6x8::render_str("Hello Rust!") - .stroke_width(1) - .translate(Point::new(0, 16)) - .into_iter(), - ); + Text::new("Hello world!", Point::zero()) + .into_styled(TextStyle::new(Font6x8, BinaryColor::On)) + .draw(&mut disp) + .unwrap(); + + Text::new("Hello Rust!", Point::new(0, 16)) + .into_styled(TextStyle::new(Font6x8, BinaryColor::On)) + .draw(&mut disp) + .unwrap(); disp.flush().unwrap(); diff --git a/release.toml b/release.toml new file mode 100644 index 0000000..af02303 --- /dev/null +++ b/release.toml @@ -0,0 +1,9 @@ +no-dev-version = true +pre-release-replacements = [ + {file="CHANGELOG.md", search="[Uu]nreleased", replace="{{version}}"}, + {file="CHANGELOG.md", search="\\.\\.\\.HEAD", replace="...{{tag_name}}"}, + {file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}"}, + {file="CHANGELOG.md", search="", replace="\n\n## [Unreleased] - ReleaseDate"}, + {file="CHANGELOG.md", search="", replace="\n[unreleased]: https://github.com/jamwaffles/sh1106/compare/{{tag_name}}...HEAD"}, +] +tag-message = "Release {{crate_name}} {{version}}" diff --git a/rustfmt.nightly.toml b/rustfmt.nightly.toml new file mode 100644 index 0000000..234303c --- /dev/null +++ b/rustfmt.nightly.toml @@ -0,0 +1,6 @@ +# Run with `cargo +nightly fmt -- --config-path ./rustfmt.nightly.toml` +# This config only works in nightly. It can be used to clean up doc comments without having to do it +# manually. + +format_code_in_doc_comments = true +merge_imports = true diff --git a/src/builder.rs b/src/builder.rs index e80035d..6cc908a 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -41,15 +41,15 @@ //! ``` use core::marker::PhantomData; -use hal; -use hal::digital::v2::OutputPin; - -use crate::displayrotation::DisplayRotation; -use crate::displaysize::DisplaySize; -use crate::interface::{I2cInterface, SpiInterface}; -use crate::mode::displaymode::DisplayMode; -use crate::mode::raw::RawMode; -use crate::properties::DisplayProperties; +use hal::{self, digital::v2::OutputPin}; + +use crate::{ + displayrotation::DisplayRotation, + displaysize::DisplaySize, + interface::{I2cInterface, SpiInterface}, + mode::{displaymode::DisplayMode, raw::RawMode}, + properties::DisplayProperties, +}; /// Builder struct. Driver options and interface are set using its methods. #[derive(Clone, Copy)] diff --git a/src/interface/i2c.rs b/src/interface/i2c.rs index 3006da2..543cb3b 100644 --- a/src/interface/i2c.rs +++ b/src/interface/i2c.rs @@ -3,8 +3,7 @@ use hal; use super::DisplayInterface; -use crate::command::Page; -use crate::Error; +use crate::{command::Page, Error}; /// SH1106 I2C communication interface pub struct I2cInterface { diff --git a/src/interface/mod.rs b/src/interface/mod.rs index 488804f..032dee1 100644 --- a/src/interface/mod.rs +++ b/src/interface/mod.rs @@ -17,8 +17,9 @@ //! # use hal::prelude::*; //! # use hal::stm32f103xx::I2C1; //! # use sh1106::interface::I2cInterface; -//! type OledDisplay = -//! GraphicsMode>, PB9>)>>>; +//! type OledDisplay = GraphicsMode< +//! I2cInterface>, PB9>)>>, +//! >; //! ``` //! //! Here's one for SPI1 on an STM32F103xx: @@ -63,5 +64,4 @@ pub trait DisplayInterface { fn send_data(&mut self, buf: &[u8]) -> Result<(), Self::Error>; } -pub use self::i2c::I2cInterface; -pub use self::spi::SpiInterface; +pub use self::{i2c::I2cInterface, spi::SpiInterface}; diff --git a/src/interface/spi.rs b/src/interface/spi.rs index 5994df4..5a44918 100644 --- a/src/interface/spi.rs +++ b/src/interface/spi.rs @@ -1,7 +1,6 @@ //! sh1106 SPI interface -use hal; -use hal::digital::v2::OutputPin; +use hal::{self, digital::v2::OutputPin}; use super::DisplayInterface; use crate::Error; diff --git a/src/mode/displaymode.rs b/src/mode/displaymode.rs index 304f9e4..3a17495 100644 --- a/src/mode/displaymode.rs +++ b/src/mode/displaymode.rs @@ -1,7 +1,6 @@ //! Abstraction of different operating modes for the sh1106 -use crate::interface::DisplayInterface; -use crate::properties::DisplayProperties; +use crate::{interface::DisplayInterface, properties::DisplayProperties}; /// Display mode abstraction pub struct DisplayMode(pub MODE); diff --git a/src/mode/graphics.rs b/src/mode/graphics.rs index 970f474..32a6223 100644 --- a/src/mode/graphics.rs +++ b/src/mode/graphics.rs @@ -15,14 +15,12 @@ //! display.flush().unwrap(); //! ``` -use hal::blocking::delay::DelayMs; -use hal::digital::v2::OutputPin; +use hal::{blocking::delay::DelayMs, digital::v2::OutputPin}; -use crate::displayrotation::DisplayRotation; -use crate::interface::DisplayInterface; -use crate::mode::displaymode::DisplayModeTrait; -use crate::properties::DisplayProperties; -use crate::Error; +use crate::{ + displayrotation::DisplayRotation, interface::DisplayInterface, + mode::displaymode::DisplayModeTrait, properties::DisplayProperties, Error, +}; const BUFFER_SIZE: usize = 132 * 64 / 8; @@ -165,39 +163,41 @@ where } #[cfg(feature = "graphics")] -extern crate embedded_graphics; -#[cfg(feature = "graphics")] -use self::embedded_graphics::{ +use embedded_graphics::{ drawable, + geometry::Size, pixelcolor::{ raw::{RawData, RawU1}, BinaryColor, }, - Drawing, + DrawTarget, }; #[cfg(feature = "graphics")] -impl Drawing for GraphicsMode +impl DrawTarget for GraphicsMode where DI: DisplayInterface, { - fn draw(&mut self, item_pixels: T) - where - T: IntoIterator>, - { - // Filter out pixels that are off the top left of the screen - let on_screen_pixels = item_pixels - .into_iter() - .filter(|drawable::Pixel(point, _)| point.x >= 0 && point.y >= 0); - - for drawable::Pixel(point, color) in on_screen_pixels { - // NOTE: The filter above means the coordinate conversions from `i32` to `u32` should - // never error. - self.set_pixel( - point.x as u32, - point.y as u32, - RawU1::from(color).into_inner(), - ); + type Error = DI::Error; + + fn draw_pixel(&mut self, pixel: drawable::Pixel) -> Result<(), Self::Error> { + let drawable::Pixel(pos, color) = pixel; + + // Guard against negative values. All positive i32 values from `pos` can be represented in + // the `u32`s that `set_pixel()` accepts... + if pos.x < 0 || pos.y < 0 { + return Ok(()); } + + // ... which makes the `as` coercions here safe. + self.set_pixel(pos.x as u32, pos.y as u32, RawU1::from(color).into_inner()); + + Ok(()) + } + + fn size(&self) -> Size { + let (w, h) = self.get_dimensions(); + + Size::new(w as u32, h as u32) } } diff --git a/src/mode/mod.rs b/src/mode/mod.rs index 70e3258..4adc0ed 100644 --- a/src/mode/mod.rs +++ b/src/mode/mod.rs @@ -7,5 +7,4 @@ pub mod displaymode; pub mod graphics; pub mod raw; -pub use self::graphics::GraphicsMode; -pub use self::raw::RawMode; +pub use self::{graphics::GraphicsMode, raw::RawMode}; diff --git a/src/mode/raw.rs b/src/mode/raw.rs index 2a28118..326714d 100644 --- a/src/mode/raw.rs +++ b/src/mode/raw.rs @@ -4,9 +4,9 @@ //! builder. Used as a source to coerce the driver into richer modes like //! [`GraphicsMode`](../graphics/index.html). -use crate::interface::DisplayInterface; -use crate::mode::displaymode::DisplayModeTrait; -use crate::properties::DisplayProperties; +use crate::{ + interface::DisplayInterface, mode::displaymode::DisplayModeTrait, properties::DisplayProperties, +}; /// Raw display mode pub struct RawMode diff --git a/src/prelude.rs b/src/prelude.rs index ae00caa..f668792 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,6 +1,8 @@ //! Crate prelude -pub use super::displayrotation::DisplayRotation; -pub use super::displaysize::DisplaySize; -pub use super::interface::{I2cInterface, SpiInterface}; -pub use super::mode::GraphicsMode; +pub use super::{ + displayrotation::DisplayRotation, + displaysize::DisplaySize, + interface::{I2cInterface, SpiInterface}, + mode::GraphicsMode, +}; diff --git a/src/properties.rs b/src/properties.rs index 8b1b230..73b1533 100644 --- a/src/properties.rs +++ b/src/properties.rs @@ -1,9 +1,11 @@ //! Container to store and set display properties -use crate::command::{Command, VcomhLevel}; -use crate::displayrotation::DisplayRotation; -use crate::displaysize::DisplaySize; -use crate::interface::DisplayInterface; +use crate::{ + command::{Command, VcomhLevel}, + displayrotation::DisplayRotation, + displaysize::DisplaySize, + interface::DisplayInterface, +}; /// Display properties struct pub struct DisplayProperties { @@ -136,7 +138,7 @@ where /// let disp = DisplayProperties::new( /// interface, /// DisplaySize::Display128x64, - /// DisplayRotation::Rotate0 + /// DisplayRotation::Rotate0, /// ); /// assert_eq!(disp.get_dimensions(), (128, 64)); /// @@ -144,7 +146,7 @@ where /// let rotated_disp = DisplayProperties::new( /// interface, /// DisplaySize::Display128x64, - /// DisplayRotation::Rotate90 + /// DisplayRotation::Rotate90, /// ); /// assert_eq!(rotated_disp.get_dimensions(), (64, 128)); /// ```