Compare commits
4 commits
9ef6b48de0
...
f0d7abdf0e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f0d7abdf0e | ||
|
|
21ae0e4968 | ||
|
|
fb05e624b7 | ||
|
|
ba5274e726 |
8 changed files with 118 additions and 87 deletions
|
|
@ -10,6 +10,7 @@ import { partyApp } from "./routes/party";
|
||||||
import { partySocketApp, pubsub } from "./routes/party-socket";
|
import { partySocketApp, pubsub } from "./routes/party-socket";
|
||||||
import { quizRoutes } from "./routes/quiz.ts";
|
import { quizRoutes } from "./routes/quiz.ts";
|
||||||
import { statsApp } from "./routes/stats.ts";
|
import { statsApp } from "./routes/stats.ts";
|
||||||
|
import { deviceSocketApp } from "./routes/device-socket.ts";
|
||||||
|
|
||||||
const app = new Elysia()
|
const app = new Elysia()
|
||||||
.use(betterAuthElysia)
|
.use(betterAuthElysia)
|
||||||
|
|
@ -20,7 +21,8 @@ const app = new Elysia()
|
||||||
.use(partyApp)
|
.use(partyApp)
|
||||||
.use(partyAnalysisApp)
|
.use(partyAnalysisApp)
|
||||||
.use(partySocketApp)
|
.use(partySocketApp)
|
||||||
.use(quizRoutes)
|
.use(quizRoutes)
|
||||||
|
.use(deviceSocketApp)
|
||||||
.get("/", () => ({ ok: true })),
|
.get("/", () => ({ ok: true })),
|
||||||
)
|
)
|
||||||
.listen(4000);
|
.listen(4000);
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import {
|
||||||
userTopic,
|
userTopic,
|
||||||
} from "./party-socket";
|
} from "./party-socket";
|
||||||
|
|
||||||
export const partySocketApp = new Elysia().group("/dev-socket", (app) =>
|
export const deviceSocketApp = new Elysia().group("/dev-socket", (app) =>
|
||||||
app
|
app
|
||||||
.get("/test", () => ({ ok: 1 }))
|
.get("/test", () => ({ ok: 1 }))
|
||||||
.ws("/ws", {
|
.ws("/ws", {
|
||||||
|
|
|
||||||
|
|
@ -2,19 +2,28 @@ import type {
|
||||||
PartySocketEvent,
|
PartySocketEvent,
|
||||||
PartyState,
|
PartyState,
|
||||||
} from "../api/src/party-types";
|
} from "../api/src/party-types";
|
||||||
let ws: WebSocket | null = new WebSocket("ws://localhost:3000/api/dev-socket/ws");
|
|
||||||
|
let last_ep_port: null|number = null
|
||||||
|
let last_ep_addr: null|string = null
|
||||||
|
|
||||||
const socket = await Bun.udpSocket({
|
const socket = await Bun.udpSocket({
|
||||||
port: 7070,
|
port: 7070,
|
||||||
socket: {
|
socket: {
|
||||||
data(socket, buf, port, addr) {
|
data(socket, buf, port, addr) {
|
||||||
console.log(`message from ${addr}:${port}:`);
|
// console.log(`message from ${addr}:${port}:`);
|
||||||
console.log(buf.toString());
|
last_ep_addr = addr
|
||||||
|
last_ep_port = port
|
||||||
|
const str = buf.toString();
|
||||||
|
console.log(str);
|
||||||
|
const opts = str.split(" ").map(t => t.trim().split("="))
|
||||||
|
const parsedOpts = Object.fromEntries(opts)
|
||||||
|
const { in1, in2, in3, in4, angle } = parsedOpts
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
let ws: WebSocket | null = new WebSocket("ws://localhost:4000/api/dev-socket/ws");
|
||||||
|
|
||||||
ws.onerror = e => {
|
ws.onerror = e => {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
|
|
@ -36,8 +45,9 @@ ws.onmessage = e => {
|
||||||
const { currentQuestion } = partyData
|
const { currentQuestion } = partyData
|
||||||
console.log(currentQuestion)
|
console.log(currentQuestion)
|
||||||
let text = currentQuestion?.text
|
let text = currentQuestion?.text
|
||||||
if (text) {
|
if (text && last_ep_port !== null && last_ep_addr !== null) {
|
||||||
ws?.send(text)
|
socket.send(text, last_ep_port, last_ep_addr)
|
||||||
|
// ws?.send(text)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
57
pico/src/buffer.rs
Normal file
57
pico/src/buffer.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
use core::{convert::Infallible, ops::Deref};
|
||||||
|
|
||||||
|
use arrayvec::ArrayVec;
|
||||||
|
use embassy_futures::yield_now;
|
||||||
|
use embassy_net::Stack;
|
||||||
|
|
||||||
|
pub struct WriteBuffer<const CAP: usize>(ArrayVec<u8, CAP>);
|
||||||
|
|
||||||
|
impl<const CAP: usize> Deref for WriteBuffer<CAP> {
|
||||||
|
type Target = [u8];
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const CAP: usize> WriteBuffer<CAP> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self(ArrayVec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.0.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const CAP: usize> embedded_io::ErrorType for WriteBuffer<CAP> {
|
||||||
|
type Error = Infallible;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const CAP: usize> embedded_io::Write for WriteBuffer<CAP> {
|
||||||
|
#[inline]
|
||||||
|
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||||
|
let _ = self.0.try_extend_from_slice(buf); //silently fails!
|
||||||
|
Ok(buf.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
|
||||||
|
self.write(buf)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn flush(&mut self) -> Result<(), Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 {
|
||||||
|
loop {
|
||||||
|
if let Some(config) = stack.config_v4() {
|
||||||
|
return config.clone();
|
||||||
|
}
|
||||||
|
yield_now().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
109
pico/src/main.rs
109
pico/src/main.rs
|
|
@ -1,23 +1,18 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
use arrayvec::ArrayVec;
|
|
||||||
use core::convert::Infallible;
|
|
||||||
use core::net::SocketAddrV4;
|
use core::net::SocketAddrV4;
|
||||||
use core::ops::Deref;
|
|
||||||
use core::str::FromStr;
|
use core::str::FromStr;
|
||||||
use embassy_net::tcp::ConnectError;
|
use embassy_net::tcp::TcpSocket;
|
||||||
use embassy_net::udp::{PacketMetadata, UdpMetadata, UdpSocket};
|
use embassy_net::udp::{PacketMetadata, UdpMetadata, UdpSocket};
|
||||||
use embedded_io::ReadReady;
|
|
||||||
|
|
||||||
|
use crate::buffer::{WriteBuffer, wait_for_config};
|
||||||
use ag_lcd::{Blink, Cursor, Display, LcdDisplay};
|
use ag_lcd::{Blink, Cursor, Display, LcdDisplay};
|
||||||
use as5600::As5600;
|
use as5600::As5600;
|
||||||
use cyw43::{JoinOptions, aligned_bytes};
|
use cyw43::{JoinOptions, aligned_bytes};
|
||||||
use cyw43_pio::{DEFAULT_CLOCK_DIVIDER, PioSpi};
|
use cyw43_pio::{DEFAULT_CLOCK_DIVIDER, PioSpi};
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_futures::yield_now;
|
|
||||||
use embassy_net::tcp::client::{TcpClient, TcpClientState};
|
|
||||||
use embassy_net::{Stack, StackResources};
|
use embassy_net::{Stack, StackResources};
|
||||||
use embassy_rp::clocks::RoscRng;
|
use embassy_rp::clocks::RoscRng;
|
||||||
use embassy_rp::gpio::{Input, Level, Output};
|
use embassy_rp::gpio::{Input, Level, Output};
|
||||||
|
|
@ -29,8 +24,11 @@ use embassy_rp::{peripherals::USB, usb};
|
||||||
use embassy_time::{Delay, Duration, Timer};
|
use embassy_time::{Delay, Duration, Timer};
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
use ufmt::{uWrite, uwrite};
|
use ufmt::{uWrite, uwrite};
|
||||||
|
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
|
mod buffer;
|
||||||
|
|
||||||
bind_interrupts!(struct Irqs {
|
bind_interrupts!(struct Irqs {
|
||||||
PIO0_IRQ_0 => InterruptHandler<PIO0>;
|
PIO0_IRQ_0 => InterruptHandler<PIO0>;
|
||||||
DMA_IRQ_0 => dma::InterruptHandler<DMA_CH0>;
|
DMA_IRQ_0 => dma::InterruptHandler<DMA_CH0>;
|
||||||
|
|
@ -55,7 +53,7 @@ async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'sta
|
||||||
runner.run().await
|
runner.run().await
|
||||||
}
|
}
|
||||||
|
|
||||||
const WIFI_NETWORK: &str = "aura";
|
const WIFI_NETWORK: &str = "flamme";
|
||||||
const WIFI_PASSWORD: &str = "12345678";
|
const WIFI_PASSWORD: &str = "12345678";
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
|
|
@ -98,15 +96,15 @@ async fn main(spawner: Spawner) {
|
||||||
let edelay = &mut Delay;
|
let edelay = &mut Delay;
|
||||||
|
|
||||||
let mut lcd: LcdDisplay<_, _> = LcdDisplay::new(
|
let mut lcd: LcdDisplay<_, _> = LcdDisplay::new(
|
||||||
Output::new(p.PIN_14, Level::Low),
|
|
||||||
Output::new(p.PIN_15, Level::Low),
|
Output::new(p.PIN_15, Level::Low),
|
||||||
|
Output::new(p.PIN_14, Level::Low),
|
||||||
edelay,
|
edelay,
|
||||||
)
|
)
|
||||||
.with_half_bus(
|
.with_half_bus(
|
||||||
Output::new(p.PIN_10, Level::Low),
|
|
||||||
Output::new(p.PIN_11, Level::Low),
|
|
||||||
Output::new(p.PIN_12, Level::Low),
|
|
||||||
Output::new(p.PIN_13, Level::Low),
|
Output::new(p.PIN_13, Level::Low),
|
||||||
|
Output::new(p.PIN_12, Level::Low),
|
||||||
|
Output::new(p.PIN_11, Level::Low),
|
||||||
|
Output::new(p.PIN_10, Level::Low),
|
||||||
)
|
)
|
||||||
.with_display(Display::On)
|
.with_display(Display::On)
|
||||||
.with_blink(Blink::On)
|
.with_blink(Blink::On)
|
||||||
|
|
@ -168,22 +166,29 @@ async fn main(spawner: Spawner) {
|
||||||
let in4 = Input::new(p.PIN_21, embassy_rp::gpio::Pull::Up);
|
let in4 = Input::new(p.PIN_21, embassy_rp::gpio::Pull::Up);
|
||||||
|
|
||||||
let mut rx_buffer = [0; 4096];
|
let mut rx_buffer = [0; 4096];
|
||||||
let mut rx_meta = [PacketMetadata::EMPTY; 16];
|
// let mut rx_meta = [PacketMetadata::EMPTY; 16];
|
||||||
let mut tx_buffer = [0; 4096];
|
let mut tx_buffer = [0; 4096];
|
||||||
let mut tx_meta = [PacketMetadata::EMPTY; 16];
|
// let mut tx_meta = [PacketMetadata::EMPTY; 16];
|
||||||
|
|
||||||
let mut socket = UdpSocket::new(
|
// let mut socket = UdpSocket::new(
|
||||||
stack,
|
// stack,
|
||||||
&mut rx_meta,
|
// &mut rx_meta,
|
||||||
&mut rx_buffer,
|
// &mut rx_buffer,
|
||||||
&mut tx_meta,
|
// &mut tx_meta,
|
||||||
&mut tx_buffer,
|
// &mut tx_buffer,
|
||||||
);
|
// );
|
||||||
socket.bind(7070).unwrap();
|
// socket.bind(7070).unwrap();
|
||||||
|
|
||||||
let host_addr = embassy_net::Ipv4Address::from_str("192.168.12.1").unwrap();
|
let host_addr = embassy_net::Ipv4Address::from_str("84.238.32.253").unwrap();
|
||||||
let target = UdpMetadata::from(SocketAddrV4::new(host_addr, 7070));
|
// let target = UdpMetadata::from(SocketAddrV4::new(host_addr, 7070));
|
||||||
uwrite!(lcd, "udp.");
|
let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
|
||||||
|
socket.set_timeout(Some(Duration::from_secs(10)));
|
||||||
|
if let Err(e) = socket.connect(SocketAddrV4::new(host_addr, 7070)).await {
|
||||||
|
uwrite!(lcd, "tcperr");
|
||||||
|
error!("tcp connect error: {}", e);
|
||||||
|
} else {
|
||||||
|
uwrite!(lcd, "tcpok");
|
||||||
|
}
|
||||||
|
|
||||||
let delay = Duration::from_millis(100);
|
let delay = Duration::from_millis(100);
|
||||||
let mut buffer = WriteBuffer::<1024>::new();
|
let mut buffer = WriteBuffer::<1024>::new();
|
||||||
|
|
@ -206,12 +211,12 @@ async fn main(spawner: Spawner) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let _ = socket.send_to(&*buffer, target).await;
|
let _ = socket.write(&*buffer).await;
|
||||||
buffer.0.clear();
|
buffer.clear();
|
||||||
}
|
}
|
||||||
if socket.may_recv() {
|
if socket.may_recv() {
|
||||||
let mut rx_buffer = [0; 4096];
|
let mut rx_buffer = [0; 4096];
|
||||||
let (n, ep) = socket.recv_from(&mut rx_buffer).await.unwrap();
|
let n = socket.read(&mut rx_buffer).await.unwrap();
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
lcd.clear();
|
lcd.clear();
|
||||||
lcd.home();
|
lcd.home();
|
||||||
|
|
@ -228,51 +233,3 @@ async fn main(spawner: Spawner) {
|
||||||
Timer::after(delay).await;
|
Timer::after(delay).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WriteBuffer<const CAP: usize>(ArrayVec<u8, CAP>);
|
|
||||||
|
|
||||||
impl<const CAP: usize> Deref for WriteBuffer<CAP> {
|
|
||||||
type Target = [u8];
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<const CAP: usize> WriteBuffer<CAP> {
|
|
||||||
fn new() -> Self {
|
|
||||||
Self(ArrayVec::new())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<const CAP: usize> embedded_io::ErrorType for WriteBuffer<CAP> {
|
|
||||||
type Error = Infallible;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<const CAP: usize> embedded_io::Write for WriteBuffer<CAP> {
|
|
||||||
#[inline]
|
|
||||||
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
|
||||||
let _ = self.0.try_extend_from_slice(buf); //silently fails!
|
|
||||||
Ok(buf.len())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
|
|
||||||
self.write(buf)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn flush(&mut self) -> Result<(), Self::Error> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 {
|
|
||||||
loop {
|
|
||||||
if let Some(config) = stack.config_v4() {
|
|
||||||
return config.clone();
|
|
||||||
}
|
|
||||||
yield_now().await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { treaty } from "@elysiajs/eden";
|
import { treaty } from "@elysiajs/eden";
|
||||||
import type { App } from "../../../api/src/index";
|
import type { App } from "../../../api/src/index";
|
||||||
|
|
||||||
export const client = treaty<App>("127.0.0.1:3000", {});
|
export const client = treaty<App>("aura.rpi1.danbulant.cloud", {});
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ function App() {
|
||||||
<MainContent>
|
<MainContent>
|
||||||
<UserInfo />
|
<UserInfo />
|
||||||
{!user?.lastSyncAt && <SyncButton />}
|
{!user?.lastSyncAt && <SyncButton />}
|
||||||
{user && <PartyQr />}
|
{user && party?.data?.status != "running" && <PartyQr />}
|
||||||
{party && !party.data && members.length > 1 && <StartParty />}
|
{party && !party.data && members.length > 1 && <StartParty />}
|
||||||
{party?.data && <PartyView />}
|
{party?.data && <PartyView />}
|
||||||
</MainContent>
|
</MainContent>
|
||||||
|
|
|
||||||
|
|
@ -11,14 +11,19 @@ const config = defineConfig({
|
||||||
plugins: [
|
plugins: [
|
||||||
devtools(),
|
devtools(),
|
||||||
tailwindcss(),
|
tailwindcss(),
|
||||||
tanstackStart(),
|
tanstackStart({
|
||||||
|
spa: {
|
||||||
|
enabled: true
|
||||||
|
}
|
||||||
|
}),
|
||||||
viteReact({
|
viteReact({
|
||||||
babel: {
|
babel: {
|
||||||
plugins: ["babel-plugin-react-compiler"],
|
plugins: ["babel-plugin-react-compiler"],
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
server: {
|
server: {
|
||||||
|
allowedHosts: ["aura.rpi1.danbulant.cloud"],
|
||||||
proxy: {
|
proxy: {
|
||||||
"/api": {
|
"/api": {
|
||||||
target: "http://localhost:4000",
|
target: "http://localhost:4000",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue