slint esp32 tokio

源码:https://github.com/xiaguangbo/slint_esp32_tokio
cpu 是 esp32c2,屏幕是 ili9341,触摸是 xpt2046,使用 spi 半双工
不使用DMA(esp-rs还没支持),SPI 40M,240*320全屏刷新为1.5秒,虽然比不了 lvgl,但类lvgl的slint是目前rust跨全平台唯一的选择
这是一个游戏,翻到两个一样的就成功,slint官网有入门示例,就是这个,然后把 .slint 和 控制逻辑拿过来直接用。就是slint平台需要稍微移植下,字体会自动打包
在这里插入图片描述

Cargo.toml

[package]
name = "esp32c2"
version = "0.1.0"
authors = ["xxx"]
edition = "2021"
resolver = "2"
rust-version = "1.71"

[profile.release]
opt-level = "s"

[profile.dev]
debug = true    # Symbols are nice and they don't increase the size on Flash
opt-level = "z"

[features]
default = ["std", "embassy", "esp-idf-svc/native"]

pio = ["esp-idf-svc/pio"]
std = ["alloc", "esp-idf-svc/binstart", "esp-idf-svc/std"]
alloc = ["esp-idf-svc/alloc"]
nightly = ["esp-idf-svc/nightly"]
experimental = ["esp-idf-svc/experimental"]
embassy = [
    "esp-idf-svc/embassy-sync",
    "esp-idf-svc/critical-section",
    "esp-idf-svc/embassy-time-driver",
]

[dependencies]
log = { version = "*", default-features = false }
esp-idf-svc = { version = "*", default-features = false }

tokio = { version = "*", features = ["rt", "time", "sync"] }
num-traits = "*"
chrono = "*"
rand = "*"
slint = { version = "*", default-features = false, features = [
    "compat-1-2",
    "renderer-software",
    "unsafe-single-threaded",
] }

[build-dependencies]
embuild = "*"
slint-build = "*"

appwindow.slint

struct TileData {
    image: image,
    image_visible: bool,
    solved: bool,
}

component MemoryTile inherits Rectangle {
    in property <bool> open_curtain;
    in property <bool> solved;
    in property <image> icon;
    callback clicked;

    height: 50px;
    width: 50px;
    border-radius: self.width / 2;
    background: solved ? #34CE57 : #3960D5;
    clip: true;

    animate background { duration: 800ms; }

    Image {
        source: icon;
        width: parent.width;
        height: parent.height;
    }

    // Left curtain
    Rectangle {
        background: #193076;
        x: 0px;
        width: open_curtain ? 0px : (parent.width / 2);
        height: parent.height;
        clip: true;

        animate width {
            duration: 250ms;
            easing: ease-in;
        }

        Image {
            width: root.width - 25px;
            height: root.height - 25px;
            x: 13px;
            y: 13px;
            source: @image-url("../icons/tile_logo.png");
        }
    }

    // Right curtain
    Rectangle {
        background: #193076;
        x: open_curtain ? parent.width : (parent.width / 2);
        width: open_curtain ? 0px : (parent.width / 2);
        height: parent.height;
        clip: true;

        animate width {
            duration: 250ms;
            easing: ease-in;
        }
        animate x {
            duration: 250ms;
            easing: ease-in;
        }

        Image {
            width: root.width - 25px;
            height: root.height - 25px;
            x: parent.width - self.width - 13px;
            y: 13px;
            source: @image-url("../icons/tile_logo.png");
        }
    }

    TouchArea {
        clicked => {
            // Delegate to the user of this element
            root.clicked();
        }

        width: 100%;
        height: 100%;
    }
}

export component AppWindow inherits Window {
    width: 240px;
    height: 320px;

    callback check_if_pair_solved();
    // Added
    in property <bool> disable_tiles;
    // Added

    in-out property <[TileData]> memory_tiles: [
        { image: @image-url("../icons/at.png") },
        { image: @image-url("../icons/balance-scale.png") },
        { image: @image-url("../icons/bicycle.png") },
        { image: @image-url("../icons/bus.png") },
        { image: @image-url("../icons/cloud.png") },
        { image: @image-url("../icons/cogs.png") },
        { image: @image-url("../icons/motorcycle.png") },
        { image: @image-url("../icons/video.png") },
    ];

    for tile[i] in memory_tiles: MemoryTile {
        x: mod(i, 4) * (root.width / 4);
        y: floor(i / 4) * (root.width / 4);
        width: 50px;
        height: 50px;
        icon: tile.image;
        open_curtain: tile.image_visible || tile.solved; // 任何一个满足都打开帘子
        // propagate the solved status from the model to the tile
        solved: tile.solved;
        clicked => {
            // old: tile.image_visible = !tile.image_visible;
            // new:
            // 可不可以点击
            if (!root.disable_tiles) {
                tile.image_visible = !tile.image_visible;
                root.check_if_pair_solved();
            }
        }
    }
}

ui

use std::{borrow::Borrow, cell::RefCell, rc::Rc};

use slint::platform::{software_renderer::*, PointerEventButton, WindowAdapter, WindowEvent};
use slint::Model;
use tokio::time;

use esp_idf_svc::hal::{gpio::*, peripheral::*, spi::*};

use crate::component::{ili9341, xpt2046};

slint::include_modules!();

pub async fn work<SPI, CS, CS2, DC>(spi1: SPI, spi2: SPI, cs1: CS, cs2: CS2, dc: DC)
where
    SPI: Borrow<SpiDriver<'static>> + 'static,
    CS: Peripheral<P = CS> + OutputPin,
    CS2: Peripheral<P = CS2> + OutputPin,
    DC: Peripheral<P = DC> + OutputPin,
{
    let mut ili9341 = ili9341::ILI9341::new(spi1, cs1, dc);
    let xpt2046 = xpt2046::XPT2046::new(spi2, cs2);

    ili9341.open();

    let buffer_provider = DrawBuffer {
        display: ili9341,
        buffer: vec![Rgb565Pixel::default(); ili9341::ILI9341_WIDTH as usize].leak(),
    };

    slint::platform::set_platform(Box::new(SlintBackend {
        window: Default::default(),
        now: std::time::Instant::now().into(),
        buffer_provider: buffer_provider.into(),
        touch: xpt2046.into(),
        last_touch: None.into(),
    }))
    .unwrap();

    let main_window = AppWindow::new().unwrap();

    // Fetch the tiles from the model
    let mut tiles: Vec<TileData> = main_window.get_memory_tiles().iter().collect();
    // Duplicate them to ensure that we have pairs
    tiles.extend(tiles.clone());

    // Randomly mix the tiles
    use rand::seq::SliceRandom;
    let mut rng = rand::thread_rng();
    tiles.shuffle(&mut rng);

    // Assign the shuffled Vec to the model property
    let tiles_model = std::rc::Rc::new(slint::VecModel::from(tiles));
    main_window.set_memory_tiles(tiles_model.clone().into());

    let main_window_weak = main_window.as_weak();
    // 点击的回调函数
    main_window.on_check_if_pair_solved(move || {
        // 如果元素的(image_visible && !solved)为真,则得到他
        // 就是被打开看的且没有被标记的对象
        let mut flipped_tiles = tiles_model
            .iter()
            .enumerate()
            .filter(|(_, tile)| tile.image_visible && !tile.solved);

        // 当检查出有两个这样的元素就进入判断
        if let (Some((t1_idx, mut t1)), Some((t2_idx, mut t2))) =
            (flipped_tiles.next(), flipped_tiles.next())
        {
            let is_pair_solved = t1 == t2; // 比较两个元素的值是不是一样的,包括图片的 rgba 和元素属性,也就是 TileData 的所有成员

            // 一样
            if is_pair_solved {
                t1.solved = true; // 彻底打开帘子
                tiles_model.set_row_data(t1_idx, t1);
                t2.solved = true;
                tiles_model.set_row_data(t2_idx, t2);
            }
            // 不一样
            else {
                let main_window = main_window_weak.unwrap();
                main_window.set_disable_tiles(true); // 防止继续点击
                let tiles_model = tiles_model.clone();

                // 延时 1s
                slint::Timer::single_shot(std::time::Duration::from_secs(1), move || {
                    main_window.set_disable_tiles(false); // 可继续点击
                    t1.image_visible = false; // 关闭帘子
                    tiles_model.set_row_data(t1_idx, t1);
                    t2.image_visible = false;
                    tiles_model.set_row_data(t2_idx, t2);
                });
            }
        }
    });

    loop {
        slint::run_event_loop().unwrap();
        time::sleep(time::Duration::from_millis(20)).await;
    }
}

pub struct SlintBackend<'a, SPI, DC>
where
    SPI: Borrow<SpiDriver<'a>> + 'a,
    DC: Peripheral<P = DC> + OutputPin,
{
    window: RefCell<Option<Rc<MinimalSoftwareWindow>>>,
    now: RefCell<std::time::Instant>,
    buffer_provider: RefCell<DrawBuffer<'a, SPI, DC>>,
    touch: RefCell<xpt2046::XPT2046<'a, SPI>>,
    last_touch: RefCell<Option<slint::LogicalPosition>>,
}

impl<'a, SPI, DC> slint::platform::Platform for SlintBackend<'a, SPI, DC>
where
    SPI: Borrow<SpiDriver<'a>> + 'a,
    DC: Peripheral<P = DC> + OutputPin,
{
    fn create_window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, slint::PlatformError> {
        let window = MinimalSoftwareWindow::new(RepaintBufferType::ReusedBuffer);

        self.window.replace(Some(window.clone()));
        self.window
            .borrow()
            .as_ref()
            .unwrap()
            .set_size(slint::PhysicalSize::new(
                ili9341::ILI9341_WIDTH as u32,
                ili9341::ILI9341_HEIGHT as u32,
            ));

        Ok(window)
    }

    fn duration_since_start(&self) -> std::time::Duration {
        self.now.borrow().elapsed()
    }

    fn run_event_loop(&self) -> Result<(), slint::PlatformError> {
        let while_now = std::time::Instant::now();
        let mut touch_now = std::time::Instant::now();
        let mut touch_ed = false;

        // 连续绘制达到 100ms 就跳过
        while while_now.elapsed().as_millis() < 100 {
            slint::platform::update_timers_and_animations();

            if let Some(window) = self.window.borrow().clone() {
                if !touch_ed {
                    touch_ed = !touch_ed;
                    touch_now = std::time::Instant::now();

                    if let Some(event) = match self.touch.borrow_mut().read() {
                        Some(v) => {
                            let position = slint::PhysicalPosition::new(
                                (v.x * ili9341::ILI9341_WIDTH as f32) as i32,
                                (v.y * ili9341::ILI9341_HEIGHT as f32) as i32,
                            )
                            .to_logical(window.scale_factor());

                            Some(match self.last_touch.borrow_mut().replace(position) {
                                Some(_) => WindowEvent::PointerMoved { position },
                                _ => WindowEvent::PointerPressed {
                                    position,
                                    button: PointerEventButton::Left,
                                },
                            })
                        }
                        _ => self.last_touch.borrow_mut().take().map(|position| {
                            WindowEvent::PointerReleased {
                                position,
                                button: PointerEventButton::Left,
                            }
                        }),
                    } {
                        let is_pointer_release_event =
                            matches!(event, WindowEvent::PointerReleased { .. });

                        window.dispatch_event(event);

                        if is_pointer_release_event {
                            window.dispatch_event(WindowEvent::PointerExited);
                        }
                    }
                } else {
                    if touch_now.elapsed().as_millis() >= 20 {
                        // 每隔一段时间才能再次读取触摸,避免频繁处理
                        touch_ed = !touch_ed;
                    }
                }

                window.draw_if_needed(|renderer| {
                    renderer.render_by_line(&mut *self.buffer_provider.borrow_mut());
                });

                if !window.has_active_animations() {
                    // 如果没有需要绘制的东西就跳出,否则就继续绘制
                    break;
                }
            }
        }
        Ok(())
    }
}

struct DrawBuffer<'a, SPI, DC>
where
    SPI: Borrow<SpiDriver<'a>> + 'a,
    DC: Peripheral<P = DC> + OutputPin,
{
    display: ili9341::ILI9341<'a, SPI, DC>,
    buffer: &'a mut [Rgb565Pixel],
}

impl<'a, SPI, DC> LineBufferProvider for &mut DrawBuffer<'a, SPI, DC>
where
    SPI: Borrow<SpiDriver<'a>> + 'a,
    DC: Peripheral<P = DC> + OutputPin,
{
    type TargetPixel = Rgb565Pixel;

    fn process_line(
        &mut self,
        line: usize,
        range: std::ops::Range<usize>,
        render_fn: impl FnOnce(&mut [Rgb565Pixel]),
    ) {
        let buffer = &mut self.buffer[range.clone()];

        render_fn(buffer);
        self.display.write_pixel_slint(
            range.start as u16,
            line as u16,
            range.end as u16,
            line as u16,
            &buffer,
        );
    }
}

work

use std::{rc, thread};

use tokio::{runtime, task, time};

use esp_idf_svc::hal::{gpio, peripherals, spi};

use crate::module::*;

pub fn work() {
    thread::Builder::new()
        .stack_size(8 * 1024)
        .spawn(|| {
            task::LocalSet::new().block_on(
                &runtime::Builder::new_current_thread()
                    .enable_all()
                    .build()
                    .unwrap(),
                async {
                    let peripherals = peripherals::Peripherals::take().unwrap();

                    let spi = spi::SpiDriver::new::<spi::SPI2>(
                        peripherals.spi2,
                        peripherals.pins.gpio0,
                        peripherals.pins.gpio1,
                        Option::<gpio::AnyIOPin>::None,
                        &spi::SpiDriverConfig::new(),
                    )
                    .unwrap();

                    let spi = rc::Rc::new(spi);
                    let spi_1 = spi.clone();
                    let spi_2 = spi.clone();

                    task::spawn_local(async move {
                        ui::work(
                            spi_1,
                            spi_2,
                            peripherals.pins.gpio3,
                            peripherals.pins.gpio4,
                            peripherals.pins.gpio2,
                        )
                        .await;
                    });

                    loop {
                        time::sleep(time::Duration::MAX).await;
                    }
                },
            );
        })
        .unwrap();
}

build

fn main() {
    embuild::espidf::sysenv::output();

    slint_build::compile_with_config(
        "ui/appwindow.slint",
        slint_build::CompilerConfiguration::new()
            .embed_resources(slint_build::EmbedResourcesKind::EmbedForSoftwareRenderer),
    )
    .unwrap();
}

ili9341

use std::borrow::*;

use esp_idf_svc::hal::{delay::Delay, gpio::*, peripheral::*, prelude::*, spi::*};

use slint::platform::software_renderer::Rgb565Pixel;

pub const ILI9341_WIDTH: u16 = 240;
pub const ILI9341_HEIGHT: u16 = 320;

/*
# 初始化
第一个字节是命令
等待5ms

36, 48 左上右下竖屏、c8 右下左上竖屏、e8 左下右上横屏、28右上左下横屏
3a, 55 像素格式 565
11     退出睡眠
29     开显示、28 关显示。不会更改内存内容

# 设置区域
可设置一点、一行或一个方块,方块区域会自动换行

2a x坐标
16bit xs
16bit xe

2b y坐标
16bit ys
16bit ye

2c
16bit 565 颜色数据
*/

pub struct ILI9341<'a, SPI, DC>
where
    SPI: Borrow<SpiDriver<'a>> + 'a,
    DC: Peripheral<P = DC> + OutputPin,
{
    spi: SpiDeviceDriver<'a, SPI>,
    dc: PinDriver<'a, DC, Output>,
    line_buf: Vec<u8>,
}

impl<'a, SPI, DC> ILI9341<'a, SPI, DC>
where
    SPI: Borrow<SpiDriver<'a>> + 'a,
    DC: Peripheral<P = DC> + OutputPin,
{
    pub fn new<CS>(spi: SPI, cs: CS, dc: DC) -> Self
    where
        CS: Peripheral<P = CS> + OutputPin,
    {
        let config = config::Config::default()
            .baudrate(40.MHz().into())
            .duplex(config::Duplex::Half3Wire);

        Self {
            spi: SpiDeviceDriver::new(spi, Some(cs), &config).unwrap(),
            dc: PinDriver::output(dc).unwrap(),
            line_buf: vec![0u8; (ILI9341_WIDTH * 2) as usize],
        }
    }

    pub fn open(&mut self) {
        let delay = Delay::new_default();

        for _ in 0..2 {
            delay.delay_ms(20);
            self.write_cmd_data_u8(0x36, Some(&[0x48]));
            self.write_cmd_data_u8(0x3a, Some(&[0x55]));
            self.write_cmd_data_u8(0x11, None);
            self.write_cmd_data_u8(0x29, None);
        }
    }

    pub fn write_pixel_slint(
        &mut self,
        x: u16,
        y: u16,
        x_end: u16,
        y_end: u16,
        pixel: &[Rgb565Pixel],
    ) {
        self.write_draw_range(x, y, x_end, y_end);
        self.write_cmd_data_slint(0x2c, pixel);
    }

    fn write_cmd_data_u8(&mut self, cmd: u8, data: Option<&[u8]>) {
        self.dc.set_low().unwrap();
        self.spi.write(&[cmd]).unwrap();

        if let Some(v) = data {
            self.dc.set_high().unwrap();
            self.spi.write(v).unwrap();
        }
    }

    fn write_draw_range(&mut self, x: u16, y: u16, x_end: u16, y_end: u16) {
        let mut x_buf = [0u8; 4];
        let mut y_buf = [0u8; 4];

        x_buf[0..=1].copy_from_slice(&x.to_be_bytes());
        x_buf[2..=3].copy_from_slice(&x_end.to_be_bytes());

        y_buf[0..=1].copy_from_slice(&y.to_be_bytes());
        y_buf[2..=3].copy_from_slice(&y_end.to_be_bytes());

        self.write_cmd_data_u8(0x2a, Some(&x_buf));
        self.write_cmd_data_u8(0x2b, Some(&y_buf));
    }

    fn write_cmd_data_slint(&mut self, cmd: u8, data: &[Rgb565Pixel]) {
        let mut i = 0;
        data.iter().for_each(|v| {
            self.line_buf[i..=i + 1].copy_from_slice(v.0.to_be_bytes().as_ref());
            i += 2;
        });

        self.dc.set_low().unwrap();
        self.spi.write(&[cmd]).unwrap();

        self.dc.set_high().unwrap();
        self.spi.write(self.line_buf[0..i].as_ref()).unwrap();
    }
}

xpt2046

use std::borrow::*;

use esp_idf_svc::hal::{gpio::*, peripheral::*, prelude::*, spi::*};

/*
d0 读 x 轴
90 读 y 轴
*/

pub struct XPT2046Touch {
    pub x: f32,
    pub y: f32,
}

pub struct XPT2046<'a, SPI>
where
    SPI: Borrow<SpiDriver<'a>> + 'a,
{
    spi: SpiDeviceDriver<'a, SPI>,
}

impl<'a, SPI> XPT2046<'a, SPI>
where
    SPI: Borrow<SpiDriver<'a>> + 'a,
{
    pub fn new<CS>(spi: SPI, cs: CS) -> Self
    where
        CS: Peripheral<P = CS> + OutputPin,
    {
        let config = config::Config::default()
            .baudrate(2.MHz().into())
            .duplex(config::Duplex::Half3Wire);

        Self {
            spi: SpiDeviceDriver::new(spi, Some(cs), &config).unwrap(),
        }
    }

    pub fn read(&mut self) -> Option<XPT2046Touch> {
        let mut x_u16 = [0u16; 3];
        let mut y_u16 = [0u16; 3];

        for i in 0..x_u16.len() {
            let mut x = [0u8; 2];
            let mut y = [0u8; 2];

            self.spi
                .transaction(&mut [Operation::Write(&[0xd0]), Operation::Read(&mut x)])
                .unwrap();

            self.spi
                .transaction(&mut [Operation::Write(&[0x90]), Operation::Read(&mut y)])
                .unwrap();

            x_u16[i] = u16::from_be_bytes(x) << 1 >> 4;
            y_u16[i] = u16::from_be_bytes(y) << 1 >> 4;
        }

        x_u16.sort();
        y_u16.sort();

        // 实测最大最小值
        let x = x_u16[1].max(336).min(3847);
        let y = y_u16[1].max(184).min(3584);

        let x = (x - 336) as f32 / (3847 - 336) as f32;
        let y = (y - 184) as f32 / (3584 - 184) as f32;

        // 判断有没有触摸
        if x == 0 as f32 && y == 1 as f32 {
            None
        } else {
            Some(XPT2046Touch { x, y })
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/645822.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Windows、Linux下,基于QT的打包方法

整理这篇文档的意义在于&#xff1a;自己走了很多弯路&#xff0c;淋过雨所以想为别人撑伞&#xff0c;也方便回顾&#xff0c;仅供参考 ps: 第一次做Windows下打包&#xff0c;用了2小时&#xff0c;第二次20秒第一次做Linux(ubuntu)下打包&#xff0c;用了8小时&#xff0c;…

Linux 内核

查看内核的发行版 $ uname -r 5.4.0-150-genericcd /lib/modules/5.4.0-150-generic, 内核源码所在的位置&#xff1a;/usr/src 这里的内核源码路径&#xff08;–kernel-source-path&#xff09;即为&#xff1a; cd /usr/src/linux-headers-5.4.0-150-generic/ 临时生效: …

JMETER工具:以录制手机app为例

JMETER工具&#xff1a;以录制手机app为例子 JMETER安装和环境配置 pc需要安装jdk&#xff0c;并进行jdk的环境配置&#xff0c;安装好jdk并配置好后&#xff0c;通过命令行输入java –version出现以下界面就表示安装成功&#xff1a; &#xff08;对应的jdk版本不可太低&…

网络通信(二)

UDP通信 特点&#xff1a;无连不是先接、不可靠通信 不事先建立连接&#xff1b;发送端每次把要发送的数据&#xff08;限制在64KB内&#xff09;、接收端IP、等信息封装成一个数据包&#xff0c;发出去就不管了 java提供了一个java.net.DatagramSocket类来实现UDP通信 Dat…

第13章-循迹功能 循迹小车讲解 原理分析 STM32智能小车循迹教程 红外对管使用 PID循迹算法分析

讲解一下我们小车里面的循迹部分&#xff0c;包括红外基础使用&#xff0c;无PID循迹和有PID循迹。 第13章-循迹功能 13.1-非PID循迹功能完成 先红外对管调试 我们这里学习一下&#xff0c;如何实现循迹功能 如何才能让小车沿着黑线运动、要让小车感知到黑线的位置&#x…

【SpringBoot】SpringBoot中防止接口重复提交(单机环境和分布式环境)

&#x1f4dd;个人主页&#xff1a;哈__ 期待您的关注 目录 &#x1f33c;前言 &#x1f512;单机环境下防止接口重复提交 &#x1f4d5;导入依赖 &#x1f4c2;项目结构 &#x1f680;创建自定义注解 ✈创建AOP切面 &#x1f697;创建Conotroller &#x1f4bb;分布…

[CISCN 2024] Crypto部分复现

文章目录 OvOez_rsacheckin浅记一下 迟来的文章 OvO 题目描述&#xff1a; from Crypto.Util.number import * from secret import flagnbits 512 p getPrime(nbits) q getPrime(nbits) n p * q phi (p-1) * (q-1) while True:kk getPrime(128)rr kk 2e 65537 kk …

3d打印问题总结

1.打印拉丝&#xff1a;https://zhuanlan.zhihu.com/p/152221550 解决方案&#xff1a;温度过高&#xff0c;PLA材料材料喷嘴温度一般设置为200度比较合适。

string OJ题

下面分享一下string做题心得 1. 明白字符串中存储的数字为0 8 9与0 8 9 完全不同&#xff0c;字符0其实在串中存储的是48&#xff0c;要有意识的转化。字符串中如果存数字8&#xff0c;意味着存了BS&#xff08;退格&#xff09; 例如1&#xff1a; 算出结果为5&#xff0c;存…

网上打印试卷的步骤是什么

对于学生和家长来说&#xff0c;打印试卷是日常学习中的一项重要需求。那么&#xff0c;如何在网上方便地打印试卷呢&#xff1f;下面&#xff0c;就让我来为您介绍琢贝云打印的试卷打印步骤。 一、选择琢贝云打印的原因 支持多种文件格式打印&#xff0c;包括图片、PPT、PDF、…

20.SkyWalking

一.简介 SkyWalking用于应用性能监控、分布式链路跟踪、诊断&#xff1a; 参考连接如下&#xff1a; https://github.com/apache/skywalking https://skywalking.apache.org/docs/ 二.示例 通过官网连接进入下载页面&#xff1a;https://archive.apache.org/dist/skywalkin…

2024年【T电梯修理】考试内容及T电梯修理新版试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年【T电梯修理】考试内容及T电梯修理新版试题&#xff0c;包含T电梯修理考试内容答案和解析及T电梯修理新版试题练习。安全生产模拟考试一点通结合国家T电梯修理考试最新大纲及T电梯修理考试真题汇总&#xff0c;…

k8s中yaml文件配置指定私有镜像仓库

1. yaml文件介绍 2. 如何快速编写yaml文件 1&#xff09;如果有已存在的pod时可以 kubectl get pod xxxxxx -oyaml 2&#xff09;直接假跑一次并查看 kubectl run xxxxxx --image镜像名 --dry-run -oyaml 3&#xff09;查看pod相关描述信息 kubectl explain pod 3. 编写…

linux 安装redis 并设置开机启动

个人实测 流程 1、第一步 先下载redis ** redis地址 https://download.redis.io/releases/选择你想要的版本 我下载的是 如下图 2、第二步:把下载的包放到linux里面 我用的是 XSHELL 和XFTP 放到/usr/local/java路径下 你可以随便放 3、第三步: ** 执行 以下命令 进行解压 t…

js之图表使用

今天为了给大家演示图表的使用,今天展示下切换图形的修改属性快速修改 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><script src"./js/jquery-3.7.1.js"></script><script src…

Llama 3没能逼出GPT-5!OpenAI怒“卷”To B战场,新企业级 AI 功能重磅推出!

Meta 是本周当之无愧的AI巨星&#xff01;刚刚推出的 Llama 3 凭借着强大的性能和开源生态的优势在 LLM 排行榜上迅速跃升。 按理说&#xff0c;Llama 3在开源的状态下做到了 GPT-3.7 的水平&#xff0c;必然会显得用户&#xff08;尤其是企业用户&#xff0c;他们更具备独立部…

flash-linear-attention中的Chunkwise并行算法的理解

这里提一下&#xff0c;我维护的几三个记录个人学习笔记以及社区中其它大佬们的优秀博客链接的仓库都获得了不少star&#xff0c;感谢读者们的认可&#xff0c;我也会继续在开源社区多做贡献。github主页&#xff1a;https://github.com/BBuf &#xff0c;欢迎来踩 0x0. 前言 …

老外卖27刀每月的教程已经更新

用了两天半的时间&#xff0c;边学习&#xff0c;边整理了一份老外的视频教程&#xff0c;涉及Facebook&#xff0c;YouTube&#xff0c;tiktok等大的流量平台&#xff0c;有案例&#xff0c;有分析&#xff0c;有如何做。 这个教程是老外讲的&#xff0c;没有什么玄乎的塑造价…

mysql 函数 GROUP_CONCAT 踩坑记录,日志:Row 244 was cut by GROUP_CONCAT()

mysql 函数 GROUP_CONCAT 踩坑记录&#xff0c;报错&#xff1a;Row 244 was cut by GROUP_CONCAT 结论&#xff1a;个人建议还是放在内存中拼接吧~db日志信息&#xff1a;Row 244 was cut by GROUP_CONCAT())根本原因&#xff1a;拼接的字符串长度超过 group_concat_max_len […

【LLM多模态】多模态LLM在图表处理的应用

note 在真实场景下&#xff0c;我们进行测试&#xff0c;多模态大模型在处理显著文本时表现尚可&#xff0c;但在处理细粒度文本时往往效果并不太好&#xff0c;why? ​具体原因如下&#xff1a; 首先&#xff0c;视觉编码器的分辨率对于多模态大模型的性能影响较大&#x…