Skip to content

Commit

Permalink
feat: terminal
Browse files Browse the repository at this point in the history
This is like a mega-commit which isn't nice but, this is meant primarily
for internal use so it is okay!

A lot of the additions here are self explanatory!
  • Loading branch information
mookums committed Jan 22, 2024
1 parent 1599bb0 commit 02a3aaa
Show file tree
Hide file tree
Showing 35 changed files with 461 additions and 126 deletions.
46 changes: 46 additions & 0 deletions .github/workflows/publish-to-release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: "publish"

on:
push:
branches:
- main

jobs:
publish-tauri:
permissions:
contents: write
strategy:
fail-fast: false
matrix:
platform: [macos-latest, ubuntu-20.04, windows-latest]

runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v4

- name: setup node
uses: actions/setup-node@v4
with:
node-version: 20

- name: install Rust stable
uses: dtolnay/rust-toolchain@stable

- name: install dependencies (ubuntu only)
if: matrix.platform == 'ubuntu-20.04'
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
- name: install frontend dependencies
run: yarn install # change this to npm or pnpm depending on which one you use

- uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tagName: app-v__VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version
releaseName: "App v__VERSION__"
releaseBody: "See the assets to download this version and install."
releaseDraft: true
prerelease: false
22 changes: 22 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
MIT License

Copyright (c) 2024 Muki Kiboigo

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# Tauri + Svelte + Typescript
# BQ-EVM-UI

This template should help get you started developing with Tauri, Svelte and TypeScript in Vite.
This is intended to give a GUI for interfacing with the BQ76925-EVM from TI without a USB-to-GPIO.

## Recommended IDE Setup

[VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer).
## Arduino
An Arduino file is provided in the /arduino directory that contains everything needed to interface with it over the given USB port.
130 changes: 130 additions & 0 deletions arduino/feather-evm.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#include <Wire.h>

uint16_t read_from_msp(unsigned int reg, int size) {
// This is more "standard" I2C.
// From my experience, it usually follow the flow below.
//
// Send Read Address.
// Send Read Register.
// Send Start Again (which is what the endTransmission(false) is doing)
// Send Read Address Again.
// THEN the peripheral I2C device responds with the data.

uint8_t msp_address = 0x40;
Wire.beginTransmission(msp_address);
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom(msp_address, size , true);

unsigned int returnInt = 0;
for(int i = 0; i < size; i++) {
returnInt = (returnInt << 8) | Wire.read();
}

return returnInt;
}

uint16_t read_from_bq(unsigned int reg, int size) {
// Read from BQ76925
// From: https://www.ti.com/lit/ds/symlink/bq76925.pdf?ts=1705535736818
// I2C is not really standardized so things happen however chip manus want it to.
// This chip encodes both the I2C address AND the register into one address.
uint8_t bq_group_addr = 0b0100;
uint8_t bq_address = (bq_group_addr << 3) + reg;
Wire.beginTransmission(bq_address);
Wire.endTransmission(false);
Wire.requestFrom((bq_address), size);

unsigned int returnInt = 0;
for(int i = 0; i < size; i++) {
returnInt = (returnInt << 8) | Wire.read();
}

return returnInt;
}

void write_to_bq(unsigned int reg, uint8_t data) {
// Write to BQ76925
// From: https://www.ti.com/lit/ds/symlink/bq76925.pdf?ts=1705535736818
// I2C is not really standardized so things happen however chip manus want it to.
// This chip encodes both the I2C address AND the register into one address.
uint8_t bq_group_addr = 0b0100;
uint8_t bq_address = ((bq_group_addr << 3) + reg);
Wire.beginTransmission(bq_address);
Wire.write(data);
Wire.endTransmission();
}

int get_device_from_params(String command_params) {
String device = command_params.substring(0, command_params.indexOf(' '));

int value = device.compareTo("msp");
return value == 0 ? 0 : 1;
}

int get_register_from_params(String command_params) {
String sub = command_params.substring(command_params.indexOf(' '));
String reg = sub.substring(0, command_params.indexOf(' '));
return reg.toInt();
}

int get_third_from_params(String command_params) {
String sub = command_params.substring(command_params.indexOf(' '));
String third = sub.substring(command_params.indexOf(' ')+1);
return third.toInt();
}

void setup() {
while ( !Serial.available() ) { delay( 1 ); }
Serial.begin(9600);
Wire.begin();
Wire.setClock(10000);
}

char input[128] = "";
int i = 0;

void loop() {

while(Serial.available()) {
char x = Serial.read();
input[i] = x;
if (x == '\n')
{
input[i] = 0x00;
String command = String(input);
String command_head = command.substring(0, command.indexOf(' '));
String command_params = command.substring(command.indexOf(' ') + 1);

unsigned int device = get_device_from_params(command_params);
unsigned int reg = get_register_from_params(command_params);
unsigned int third = get_third_from_params(command_params);

if(command_head.compareTo("read") == 0) {
if(device) {
// BQ
unsigned int value = read_from_bq(reg, third);
Serial.println(value);
} else {
// MSP
unsigned int value = read_from_msp(reg, third);
Serial.println(value);
}

} else if(command_head.compareTo("write") == 0){
if(device) {
write_to_bq(reg, third);
Serial.println("SUCCESS!");
} else {
Serial.println("Invalid Command | Only the 'bq' device is enable for 'write'!");
}
} else {
Serial.println("Invalid Command | Only 'read' or 'write' is allowed!");
}
i = 0;
} else {
i++;
}
}
}

3 changes: 1 addition & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tauri + Svelte + TS</title>
<title>BQ-EVM-UI</title>
</head>

<body>
Expand Down
1 change: 0 additions & 1 deletion public/svelte.svg

This file was deleted.

6 changes: 0 additions & 6 deletions public/tauri.svg

This file was deleted.

1 change: 0 additions & 1 deletion public/vite.svg

This file was deleted.

Binary file modified src-tauri/icons/128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src-tauri/icons/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src-tauri/icons/32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src-tauri/icons/512x512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src-tauri/icons/Square107x107Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src-tauri/icons/Square142x142Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src-tauri/icons/Square150x150Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src-tauri/icons/Square284x284Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src-tauri/icons/Square30x30Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src-tauri/icons/Square310x310Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src-tauri/icons/Square44x44Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src-tauri/icons/Square71x71Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src-tauri/icons/Square89x89Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src-tauri/icons/StoreLogo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src-tauri/icons/icon.icns
Binary file not shown.
Binary file modified src-tauri/icons/icon.ico
Binary file not shown.
Binary file modified src-tauri/icons/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
99 changes: 78 additions & 21 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

use ::memchr::memchr;
use serialport::SerialPort;
use serialport::{ErrorKind, SerialPort};
use std::{sync::Mutex, time::Duration};

struct PortState {
port: Mutex<Option<Box<dyn SerialPort>>>,
}

// We use U32s as status codes to send back to the Host Application.
//
// 0 means Success
// 1 means Serial Open Issue (Already Open or In Use)
// 2 means Mutex Error.

#[tauri::command]
fn print_serial_ports() -> Vec<String> {
let ports = serialport::available_ports();
Expand All @@ -27,31 +33,47 @@ fn print_serial_ports() -> Vec<String> {
}

#[tauri::command]
fn open_serial_port(port_state: tauri::State<PortState>, port_name: &str, baud_rate: u32) -> bool {
fn open_serial_port(port_state: tauri::State<PortState>, port_name: &str, baud_rate: u32) -> u32 {
let new_port_result = serialport::new(port_name, baud_rate)
.timeout(Duration::from_millis(1000))
.timeout(Duration::from_millis(5000))
.open();

let new_port = match new_port_result {
Ok(p) => p,
Err(e) => {
println!("{}", e);
return false;
}
Err(e) => match e.kind {
ErrorKind::NoDevice => return 1,
_ => return 2,
},
};

// Check the Port State.
let port_guard_result = port_state.port.lock();
match port_guard_result {
// Update the current Port
Ok(mut port) => {
println!("Port is being assigned to State");
println!("Port: {} is being attached to state", port_name);
*port = Some(new_port);
return true;
return 0;
}
Err(_) => {
return 3;
}
}
}

#[tauri::command]
fn close_serial_port(port_state: tauri::State<PortState>) -> String {
// Check the Port State.
let port_guard_result = port_state.port.lock();
match port_guard_result {
// Update the current Port
Ok(mut port) => {
println!("Port is being closed!");
*port = None;
return String::from("");
}
Err(e) => {
println!("{}", e);
return false;
return format!("{}", e);
}
}
}
Expand All @@ -75,19 +97,52 @@ fn read_from_serial_port(port_state: tauri::State<PortState>) -> String {
}
};

let mut serial_buf: [u8; 64] = [0; 64];
port.read(&mut serial_buf).expect("No Bytes!");
let mut serial_vec: Vec<u8> = Vec::new();

loop {
// Not the greatest solution for performance :3
let mut serial_buf: [u8; 1] = [0; 1];
port.read_exact(&mut serial_buf).expect("No Bytes!");

// Append the Serial Buf into the Vector
serial_buf.iter().for_each(|b| {
serial_vec.push(b.clone());
});

// Send up to New Line.
let value = memchr(b'\n', &serial_buf);
match value {
Some(index) => {
return String::from_utf8(serial_buf[0..index].to_vec()).expect("Invalid Bytes");
// Send up to New Line.
let value = memchr(b'\n', &serial_vec);
match value {
Some(_) => {
return String::from_utf8(serial_vec).expect("Invalid Bytes");
}
None => {
continue;
}
}
}
}

#[tauri::command]
fn write_to_serial_port(port_state: tauri::State<PortState>, data: String) -> bool {
// Get Mutex
let mut port_guard = match port_state.port.lock() {
Ok(p) => p,
Err(e) => {
println!("{}", e);
return false;
}
};

// Get Port from Option
let port = match &mut *port_guard {
Some(p) => p,
None => {
return String::from_utf8(serial_buf.to_vec()).expect("Invalid Bytes!");
return false;
}
}
};

port.write_all(data.as_bytes()).unwrap();
true
}

fn main() {
Expand All @@ -98,7 +153,9 @@ fn main() {
.invoke_handler(tauri::generate_handler![
print_serial_ports,
open_serial_port,
read_from_serial_port
close_serial_port,
read_from_serial_port,
write_to_serial_port
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
Expand Down
Loading

0 comments on commit 02a3aaa

Please sign in to comment.