mirror of https://github.com/4yn/slidershim
Tasoller hid
parent
a44220fed1
commit
06707302d1
116
README.md
116
README.md
|
@ -1,109 +1,9 @@
|
||||||
*Psst — looking for a more complete solution? Check out [SvelteKit](https://kit.svelte.dev), the official framework for building web applications of all sizes, with a beautiful development experience and flexible filesystem-based routing.*
|
# Todo
|
||||||
|
|
||||||
*Looking for a shareable component template instead? You can [use SvelteKit for that as well](https://kit.svelte.dev/docs#packaging) or the older [sveltejs/component-template](https://github.com/sveltejs/component-template)*
|
- input polling rate counter
|
||||||
|
- led polling rate settings
|
||||||
---
|
- settings serializer
|
||||||
|
- brokenithm server
|
||||||
# svelte app
|
- ouptut websocket
|
||||||
|
- led websocket
|
||||||
This is a project template for [Svelte](https://svelte.dev) apps. It lives at https://github.com/sveltejs/template.
|
- comments
|
||||||
|
|
||||||
To create a new project based on this template using [degit](https://github.com/Rich-Harris/degit):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npx degit sveltejs/template svelte-app
|
|
||||||
cd svelte-app
|
|
||||||
```
|
|
||||||
|
|
||||||
*Note that you will need to have [Node.js](https://nodejs.org) installed.*
|
|
||||||
|
|
||||||
|
|
||||||
## Get started
|
|
||||||
|
|
||||||
Install the dependencies...
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd svelte-app
|
|
||||||
npm install
|
|
||||||
```
|
|
||||||
|
|
||||||
...then start [Rollup](https://rollupjs.org):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
Navigate to [localhost:8080](http://localhost:8080). You should see your app running. Edit a component file in `src`, save it, and reload the page to see your changes.
|
|
||||||
|
|
||||||
By default, the server will only respond to requests from localhost. To allow connections from other computers, edit the `sirv` commands in package.json to include the option `--host 0.0.0.0`.
|
|
||||||
|
|
||||||
If you're using [Visual Studio Code](https://code.visualstudio.com/) we recommend installing the official extension [Svelte for VS Code](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). If you are using other editors you may need to install a plugin in order to get syntax highlighting and intellisense.
|
|
||||||
|
|
||||||
## Building and running in production mode
|
|
||||||
|
|
||||||
To create an optimised version of the app:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run build
|
|
||||||
```
|
|
||||||
|
|
||||||
You can run the newly built app with `npm run start`. This uses [sirv](https://github.com/lukeed/sirv), which is included in your package.json's `dependencies` so that the app will work when you deploy to platforms like [Heroku](https://heroku.com).
|
|
||||||
|
|
||||||
|
|
||||||
## Single-page app mode
|
|
||||||
|
|
||||||
By default, sirv will only respond to requests that match files in `public`. This is to maximise compatibility with static fileservers, allowing you to deploy your app anywhere.
|
|
||||||
|
|
||||||
If you're building a single-page app (SPA) with multiple routes, sirv needs to be able to respond to requests for *any* path. You can make it so by editing the `"start"` command in package.json:
|
|
||||||
|
|
||||||
```js
|
|
||||||
"start": "sirv public --single"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Using TypeScript
|
|
||||||
|
|
||||||
This template comes with a script to set up a TypeScript development environment, you can run it immediately after cloning the template with:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
node scripts/setupTypeScript.js
|
|
||||||
```
|
|
||||||
|
|
||||||
Or remove the script via:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
rm scripts/setupTypeScript.js
|
|
||||||
```
|
|
||||||
|
|
||||||
If you want to use `baseUrl` or `path` aliases within your `tsconfig`, you need to set up `@rollup/plugin-alias` to tell Rollup to resolve the aliases. For more info, see [this StackOverflow question](https://stackoverflow.com/questions/63427935/setup-tsconfig-path-in-svelte).
|
|
||||||
|
|
||||||
## Deploying to the web
|
|
||||||
|
|
||||||
### With [Vercel](https://vercel.com)
|
|
||||||
|
|
||||||
Install `vercel` if you haven't already:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install -g vercel
|
|
||||||
```
|
|
||||||
|
|
||||||
Then, from within your project folder:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd public
|
|
||||||
vercel deploy --name my-project
|
|
||||||
```
|
|
||||||
|
|
||||||
### With [surge](https://surge.sh/)
|
|
||||||
|
|
||||||
Install `surge` if you haven't already:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install -g surge
|
|
||||||
```
|
|
||||||
|
|
||||||
Then, from within your project folder:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run build
|
|
||||||
surge public my-project.surge.sh
|
|
||||||
```
|
|
||||||
|
|
|
@ -5,12 +5,23 @@ use std::io;
|
||||||
use slidershim::slider_io::{Config, Manager};
|
use slidershim::slider_io::{Config, Manager};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
// let config = Config::from_str(
|
||||||
|
// r#"{
|
||||||
|
// "deviceMode": "yuancon",
|
||||||
|
// "outputMode": "kb-32-tasoller",
|
||||||
|
// "ledMode": "reactive-8",
|
||||||
|
// "keyboardSensitivity": 50
|
||||||
|
// }"#,
|
||||||
|
// )
|
||||||
|
// .unwrap();
|
||||||
|
|
||||||
let config = Config::from_str(
|
let config = Config::from_str(
|
||||||
r#"{
|
r#"{
|
||||||
"deviceMode": "yuancon",
|
"deviceMode": "yuancon",
|
||||||
"outputMode": "kb-32-tasoller",
|
"outputMode": "kb-32-tasoller",
|
||||||
|
"keyboardSensitivity": 50,
|
||||||
"ledMode": "reactive-8",
|
"ledMode": "reactive-8",
|
||||||
"keyboardSensitivity": 50
|
"ledSensitivity": 50
|
||||||
}"#,
|
}"#,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
use std::{error, ops::DerefMut, time::Duration};
|
use std::{
|
||||||
|
error,
|
||||||
|
ops::{Deref, DerefMut},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
use rusb::{self, DeviceHandle, GlobalContext};
|
use rusb::{self, DeviceHandle, GlobalContext};
|
||||||
|
|
||||||
|
@ -9,14 +13,14 @@ use crate::slider_io::{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Buffer {
|
pub struct Buffer {
|
||||||
pub data: [u8; 128],
|
pub data: [u8; 256],
|
||||||
pub len: usize,
|
pub len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Buffer {
|
impl Buffer {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Buffer {
|
Buffer {
|
||||||
data: [0; 128],
|
data: [0; 256],
|
||||||
len: 0,
|
len: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +31,12 @@ impl Buffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
type HidReadCallback = fn(&Buffer, &mut ControllerState) -> ();
|
type HidReadCallback = fn(&Buffer, &mut ControllerState) -> ();
|
||||||
type HidLedCallback = fn(&mut Buffer, &mut LedState) -> ();
|
type HidLedCallback = fn(&mut Buffer, &LedState) -> ();
|
||||||
|
|
||||||
|
enum WriteType {
|
||||||
|
Bulk,
|
||||||
|
Interrupt,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct HidDeviceJob {
|
pub struct HidDeviceJob {
|
||||||
state: FullState,
|
state: FullState,
|
||||||
|
@ -39,6 +48,7 @@ pub struct HidDeviceJob {
|
||||||
read_callback: HidReadCallback,
|
read_callback: HidReadCallback,
|
||||||
read_buf: Buffer,
|
read_buf: Buffer,
|
||||||
|
|
||||||
|
led_write_type: WriteType,
|
||||||
led_callback: HidLedCallback,
|
led_callback: HidLedCallback,
|
||||||
led_buf: Buffer,
|
led_buf: Buffer,
|
||||||
|
|
||||||
|
@ -53,6 +63,7 @@ impl HidDeviceJob {
|
||||||
read_endpoint: u8,
|
read_endpoint: u8,
|
||||||
led_endpoint: u8,
|
led_endpoint: u8,
|
||||||
read_callback: HidReadCallback,
|
read_callback: HidReadCallback,
|
||||||
|
led_type: WriteType,
|
||||||
led_callback: HidLedCallback,
|
led_callback: HidLedCallback,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -63,6 +74,7 @@ impl HidDeviceJob {
|
||||||
led_endpoint,
|
led_endpoint,
|
||||||
read_callback,
|
read_callback,
|
||||||
read_buf: Buffer::new(),
|
read_buf: Buffer::new(),
|
||||||
|
led_write_type: led_type,
|
||||||
led_callback,
|
led_callback,
|
||||||
led_buf: Buffer::new(),
|
led_buf: Buffer::new(),
|
||||||
handle: None,
|
handle: None,
|
||||||
|
@ -71,6 +83,65 @@ impl HidDeviceJob {
|
||||||
|
|
||||||
pub fn from_config(state: &FullState, mode: &DeviceMode) -> Self {
|
pub fn from_config(state: &FullState, mode: &DeviceMode) -> Self {
|
||||||
match mode {
|
match mode {
|
||||||
|
DeviceMode::TasollerOne => Self::new(
|
||||||
|
state.clone(),
|
||||||
|
0x1ccf,
|
||||||
|
0x2333,
|
||||||
|
0x84,
|
||||||
|
0x03,
|
||||||
|
|buf, controller_state| {
|
||||||
|
if buf.len != 11 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let bits: Vec<u8> = buf
|
||||||
|
.data
|
||||||
|
.iter()
|
||||||
|
.flat_map(|x| (0..8).map(move |i| ((x) >> i) & 1))
|
||||||
|
.collect();
|
||||||
|
for i in 0..32 {
|
||||||
|
controller_state.ground_state[i] = bits[34 + i] * 255;
|
||||||
|
}
|
||||||
|
controller_state.air_state.copy_from_slice(&bits[28..34]);
|
||||||
|
},
|
||||||
|
WriteType::Bulk,
|
||||||
|
|buf, led_state| {
|
||||||
|
buf.len = 240;
|
||||||
|
buf.data[0] = 'B' as u8;
|
||||||
|
buf.data[1] = 'L' as u8;
|
||||||
|
buf.data[2] = '\x00' as u8;
|
||||||
|
buf.data[3..96].copy_from_slice(&led_state.led_state[..3 * 31]);
|
||||||
|
buf.data[96..240].fill(0);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
DeviceMode::TasollerTwo => Self::new(
|
||||||
|
state.clone(),
|
||||||
|
0x1ccf,
|
||||||
|
0x2333,
|
||||||
|
0x84,
|
||||||
|
0x03,
|
||||||
|
|buf, controller_state| {
|
||||||
|
if buf.len != 36 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
controller_state
|
||||||
|
.ground_state
|
||||||
|
.copy_from_slice(&buf.data[4..36]);
|
||||||
|
for i in 0..6 {
|
||||||
|
controller_state.air_state[i] = (buf.data[3] >> (i + 2)) & 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
WriteType::Bulk,
|
||||||
|
|buf, led_state| {
|
||||||
|
buf.len = 240;
|
||||||
|
buf.data[0] = 'B' as u8;
|
||||||
|
buf.data[1] = 'L' as u8;
|
||||||
|
buf.data[2] = '\x00' as u8;
|
||||||
|
buf.data[3..96].copy_from_slice(&led_state.led_state[..3 * 31]);
|
||||||
|
buf.data[96..240].fill(0);
|
||||||
|
},
|
||||||
|
),
|
||||||
DeviceMode::Yuancon => Self::new(
|
DeviceMode::Yuancon => Self::new(
|
||||||
state.clone(),
|
state.clone(),
|
||||||
0x1973,
|
0x1973,
|
||||||
|
@ -84,7 +155,7 @@ impl HidDeviceJob {
|
||||||
|
|
||||||
controller_state
|
controller_state
|
||||||
.ground_state
|
.ground_state
|
||||||
.clone_from_slice(&buf.data[2..34]);
|
.copy_from_slice(&buf.data[2..34]);
|
||||||
for i in 0..6 {
|
for i in 0..6 {
|
||||||
controller_state.air_state[i ^ 1] = if buf.data[0] & (1 << i) == 0 { 1 } else { 0 };
|
controller_state.air_state[i ^ 1] = if buf.data[0] & (1 << i) == 0 { 1 } else { 0 };
|
||||||
}
|
}
|
||||||
|
@ -92,21 +163,18 @@ impl HidDeviceJob {
|
||||||
controller_state.extra_state[i] = if buf.data[1] & (1 << i) == 0 { 1 } else { 0 };
|
controller_state.extra_state[i] = if buf.data[1] & (1 << i) == 0 { 1 } else { 0 };
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
WriteType::Interrupt,
|
||||||
|buf, led_state| {
|
|buf, led_state| {
|
||||||
if !led_state.dirty {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
buf.len = 31 * 2;
|
buf.len = 31 * 2;
|
||||||
buf
|
for (buf_chunk, state_chunk) in buf
|
||||||
.data
|
.data
|
||||||
.chunks_mut(2)
|
.chunks_mut(2)
|
||||||
.take(31)
|
.take(31)
|
||||||
.zip(led_state.led_state.chunks(3).rev())
|
.zip(led_state.led_state.chunks(3).rev())
|
||||||
.for_each(|(buf_chunk, state_chunk)| {
|
{
|
||||||
buf_chunk[0] = (state_chunk[0] << 3 & 0xe0) | (state_chunk[2] >> 3);
|
buf_chunk[0] = (state_chunk[0] << 3 & 0xe0) | (state_chunk[2] >> 3);
|
||||||
buf_chunk[1] = (state_chunk[1] & 0xf8) | (state_chunk[0] >> 5);
|
buf_chunk[1] = (state_chunk[1] & 0xf8) | (state_chunk[0] >> 5);
|
||||||
});
|
}
|
||||||
led_state.dirty = false;
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
_ => panic!("Not implemented"),
|
_ => panic!("Not implemented"),
|
||||||
|
@ -150,10 +218,16 @@ impl Job for HidDeviceJob {
|
||||||
// Led loop
|
// Led loop
|
||||||
{
|
{
|
||||||
let mut led_state_handle = self.state.led_state.lock().unwrap();
|
let mut led_state_handle = self.state.led_state.lock().unwrap();
|
||||||
(self.led_callback)(&mut self.led_buf, led_state_handle.deref_mut());
|
if led_state_handle.dirty {
|
||||||
|
(self.led_callback)(&mut self.led_buf, led_state_handle.deref());
|
||||||
|
led_state_handle.dirty = false;
|
||||||
if self.led_buf.len != 0 {
|
if self.led_buf.len != 0 {
|
||||||
let res = handle
|
let res = (match self.led_write_type {
|
||||||
.write_interrupt(self.led_endpoint, &self.led_buf.data, TIMEOUT)
|
WriteType::Bulk => handle.write_bulk(self.led_endpoint, &self.led_buf.data, TIMEOUT),
|
||||||
|
WriteType::Interrupt => {
|
||||||
|
handle.write_interrupt(self.led_endpoint, &self.led_buf.data, TIMEOUT)
|
||||||
|
}
|
||||||
|
})
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
if res == self.led_buf.len + 1 {
|
if res == self.led_buf.len + 1 {
|
||||||
self.led_buf.len = 0;
|
self.led_buf.len = 0;
|
||||||
|
@ -161,6 +235,7 @@ impl Job for HidDeviceJob {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn teardown(&mut self) {
|
fn teardown(&mut self) {
|
||||||
let handle = self.handle.as_mut().unwrap();
|
let handle = self.handle.as_mut().unwrap();
|
||||||
|
|
Loading…
Reference in New Issue