Compare commits
3 commits
e4e392de51
...
9ef6b48de0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ef6b48de0 | ||
|
|
3977f101ad | ||
|
|
7c51ee47b5 |
5 changed files with 109 additions and 63 deletions
|
|
@ -38,7 +38,7 @@ async function getAlbumReleaseYear({
|
||||||
type: "numeric",
|
type: "numeric",
|
||||||
text: `What's the release year of ${subject}?`,
|
text: `What's the release year of ${subject}?`,
|
||||||
correct,
|
correct,
|
||||||
range: getQuestionRange(correct, 5),
|
range: getQuestionRange(correct, 10, 3),
|
||||||
points: 10,
|
points: 10,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,10 +77,14 @@ export function getQuestionDistanceScore(
|
||||||
export function getQuestionRange(
|
export function getQuestionRange(
|
||||||
correctValue: number,
|
correctValue: number,
|
||||||
tolerance: number,
|
tolerance: number,
|
||||||
|
randomness: number,
|
||||||
): { min: number; max: number } {
|
): { min: number; max: number } {
|
||||||
|
const min = Math.floor(correctValue - tolerance);
|
||||||
|
const max = Math.ceil(correctValue + tolerance);
|
||||||
|
const range = max - min;
|
||||||
return {
|
return {
|
||||||
min: Math.floor(correctValue - tolerance),
|
min: min + Math.floor(Math.random() * range * randomness),
|
||||||
max: Math.ceil(correctValue + tolerance),
|
max: max - Math.floor(Math.random() * range * randomness),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,41 +2,45 @@ import type {
|
||||||
PartySocketEvent,
|
PartySocketEvent,
|
||||||
PartyState,
|
PartyState,
|
||||||
} from "../api/src/party-types";
|
} from "../api/src/party-types";
|
||||||
let ws: WebSocket | null = null;
|
let ws: WebSocket | null = new WebSocket("ws://localhost:3000/api/dev-socket/ws");
|
||||||
|
|
||||||
Bun.listen({
|
const socket = await Bun.udpSocket({
|
||||||
hostname: "0.0.0.0",
|
|
||||||
port: 7070,
|
port: 7070,
|
||||||
socket: {
|
socket: {
|
||||||
data(socket, data) {
|
data(socket, buf, port, addr) {
|
||||||
// in1={} in2={} in3={} in4={} angle={}
|
console.log(`message from ${addr}:${port}:`);
|
||||||
console.log("recv", data)
|
console.log(buf.toString());
|
||||||
}, // message received from client
|
},
|
||||||
open(socket) {
|
|
||||||
console.log("Connected");
|
|
||||||
ws = new WebSocket("ws://localhost:3000/api/dev-socket/ws");
|
|
||||||
|
|
||||||
ws.onmessage = e => {
|
|
||||||
const data = JSON.parse(e.data) as PartySocketEvent;
|
|
||||||
switch (data.type) {
|
|
||||||
case "party_status":
|
|
||||||
const { party: { data: { currentQuestion } } } = data;
|
|
||||||
console.log(currentQuestion)
|
|
||||||
let text = currentQuestion?.text
|
|
||||||
if (text) {
|
|
||||||
ws?.send(text)
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, // socket opened
|
|
||||||
close(socket, error) {
|
|
||||||
ws?.close();
|
|
||||||
ws = null;
|
|
||||||
}, // socket closed
|
|
||||||
drain(socket) {}, // socket ready for more data
|
|
||||||
error(socket, error) {}, // error handler
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ws.onerror = e => {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
ws.onopen = () => {
|
||||||
|
console.log("WebSocket open")
|
||||||
|
}
|
||||||
|
|
||||||
|
ws.onmessage = e => {
|
||||||
|
const data = JSON.parse(e.data) as PartySocketEvent;
|
||||||
|
console.log(data)
|
||||||
|
switch (data.type) {
|
||||||
|
case "party_status":
|
||||||
|
const { party } = data;
|
||||||
|
if (!party) return;
|
||||||
|
const partyData = party.data;
|
||||||
|
if (!partyData) return;
|
||||||
|
const { currentQuestion } = partyData
|
||||||
|
console.log(currentQuestion)
|
||||||
|
let text = currentQuestion?.text
|
||||||
|
if (text) {
|
||||||
|
ws?.send(text)
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
console.log("Started on :7070")
|
console.log("Started on :7070")
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,12 @@
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
|
use core::convert::Infallible;
|
||||||
|
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::ConnectError;
|
||||||
|
use embassy_net::udp::{PacketMetadata, UdpMetadata, UdpSocket};
|
||||||
use embedded_io::ReadReady;
|
use embedded_io::ReadReady;
|
||||||
|
|
||||||
use ag_lcd::{Blink, Cursor, Display, LcdDisplay};
|
use ag_lcd::{Blink, Cursor, Display, LcdDisplay};
|
||||||
|
|
@ -164,34 +168,25 @@ 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 tx_buffer = [0; 4096];
|
let mut tx_buffer = [0; 4096];
|
||||||
let mut socket = embassy_net::tcp::TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
|
let mut tx_meta = [PacketMetadata::EMPTY; 16];
|
||||||
socket.set_timeout(Some(Duration::from_secs(10)));
|
|
||||||
|
let mut socket = UdpSocket::new(
|
||||||
|
stack,
|
||||||
|
&mut rx_meta,
|
||||||
|
&mut rx_buffer,
|
||||||
|
&mut tx_meta,
|
||||||
|
&mut tx_buffer,
|
||||||
|
);
|
||||||
|
socket.bind(7070).unwrap();
|
||||||
|
|
||||||
led.set_low();
|
|
||||||
info!("Connecting...");
|
|
||||||
uwrite!(lcd, "con2.");
|
|
||||||
let host_addr = embassy_net::Ipv4Address::from_str("192.168.12.1").unwrap();
|
let host_addr = embassy_net::Ipv4Address::from_str("192.168.12.1").unwrap();
|
||||||
if let Err(e) = socket.connect((host_addr, 7070)).await {
|
let target = UdpMetadata::from(SocketAddrV4::new(host_addr, 7070));
|
||||||
lcd.clear();
|
uwrite!(lcd, "udp.");
|
||||||
uwrite!(lcd, "conerr");
|
|
||||||
Timer::after(Duration::from_micros(100)).await;
|
|
||||||
lcd.set_position(0, 1);
|
|
||||||
let emsg = match e {
|
|
||||||
ConnectError::ConnectionReset => "rst",
|
|
||||||
ConnectError::InvalidState => "inv",
|
|
||||||
ConnectError::TimedOut => "tout",
|
|
||||||
ConnectError::NoRoute => "nroute",
|
|
||||||
};
|
|
||||||
uwrite!(lcd, "{}", emsg);
|
|
||||||
warn!("connect error: {:?}", e);
|
|
||||||
} else {
|
|
||||||
uwrite!(lcd, "conok");
|
|
||||||
}
|
|
||||||
info!("Connected to {:?}", socket.remote_endpoint());
|
|
||||||
|
|
||||||
let delay = Duration::from_millis(100);
|
let delay = Duration::from_millis(100);
|
||||||
let mut buffer = ArrayVec::<u8, 512>::new();
|
let mut buffer = WriteBuffer::<1024>::new();
|
||||||
loop {
|
loop {
|
||||||
let in1 = in1.is_low();
|
let in1 = in1.is_low();
|
||||||
let in2 = in2.is_low();
|
let in2 = in2.is_low();
|
||||||
|
|
@ -201,7 +196,7 @@ async fn main(spawner: Spawner) {
|
||||||
{
|
{
|
||||||
use embedded_io::Write;
|
use embedded_io::Write;
|
||||||
let _ = core::writeln!(
|
let _ = core::writeln!(
|
||||||
&mut buffer[..],
|
&mut buffer,
|
||||||
"in1={} in2={} in3={} in4={} angle={}",
|
"in1={} in2={} in3={} in4={} angle={}",
|
||||||
in1,
|
in1,
|
||||||
in2,
|
in2,
|
||||||
|
|
@ -211,12 +206,12 @@ async fn main(spawner: Spawner) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
use embedded_io_async::Write;
|
let _ = socket.send_to(&*buffer, target).await;
|
||||||
let _ = socket.write_all(&*buffer).await;
|
buffer.0.clear();
|
||||||
}
|
}
|
||||||
if socket.read_ready().unwrap_or(false) {
|
if socket.may_recv() {
|
||||||
let mut rx_buffer = [0; 4096];
|
let mut rx_buffer = [0; 4096];
|
||||||
let n = socket.read(&mut rx_buffer).await.unwrap_or(0);
|
let (n, ep) = socket.recv_from(&mut rx_buffer).await.unwrap();
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
lcd.clear();
|
lcd.clear();
|
||||||
lcd.home();
|
lcd.home();
|
||||||
|
|
@ -234,6 +229,45 @@ async fn main(spawner: Spawner) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 {
|
||||||
loop {
|
loop {
|
||||||
if let Some(config) = stack.config_v4() {
|
if let Some(config) = stack.config_v4() {
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,11 @@ export function Question() {
|
||||||
setSelectedValue(question.type === "numeric" ? question.range.min : null);
|
setSelectedValue(question.type === "numeric" ? question.range.min : null);
|
||||||
}, [question]);
|
}, [question]);
|
||||||
|
|
||||||
if (!question) return null;
|
if (!question) return (
|
||||||
|
<Section>
|
||||||
|
<SectionTitle>Preparing quiz...</SectionTitle>
|
||||||
|
</Section>
|
||||||
|
);
|
||||||
|
|
||||||
const partyId = party.id;
|
const partyId = party.id;
|
||||||
const timeLeft = formatTimeLeft(question.endTimestamp - now);
|
const timeLeft = formatTimeLeft(question.endTimestamp - now);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue