Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update README.md #46

Merged
merged 8 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added CONTRIBUTING.md
Empty file.
187 changes: 119 additions & 68 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,178 +1,229 @@
<p align="center">
<br><img src="imgs/scope-logo.png" width="800">
<br><img src="imgs/scope-logo.png" width="800" alt="Scope Banner">
<br><img src="https://github.com/matheuswhite/scope-rs/actions/workflows/rust.yml/badge.svg" alt="Build Status">
<a href="https://opensource.org/licenses/BSD-3-Clause"><img src="https://img.shields.io/badge/License-BSD_3--Clause-blue.svg"></a>
<a href="https://crates.io/creates/scope-rs"><img src="https://img.shields.io/crates/v/scope-rs.svg" alt="Version info"></a>
<br><b>Scope</b> is a multi-platform serial monitor with user-extensible features.
</p>

<p align="center">
<a href="#send-data">Key Features</a> •
<a href="#scope-vs-others">Scope vs Other</a> •
<a href="#installation">Installation</a> •
<a href="#how-to-use">How to Use</a> •
<a href="#project-goals">Project Goals</a>
</p>

### Send Data

With `Scope` serial monitor you can use the command bar (at bottom of screen) to send data.
With `Scope`, you can type a message on the command bar (at bottom) and hit `Enter` to send it through the serial port.

![Send data gif]()
![Send data gif](videos/send_data.gif)

### Send in Hexadecimal

You also can send data in hexadecimal format. To do this, type `$` and write your hexadecimal data. The hexadecimal
could have spaces and commas inside. The scope will send without spaces and commas).
You also can send bytes in hexadecimal. To do it, type `$` and write your bytes in a hexadecimal format. The message
can have spaces and commas as separators (`Scope` will send the bytes of message without spaces and commas).

![Send hex gif]()
![Send hex gif](videos/hexa.gif)

### Send Commands

You can also send commands using the command bar. To send a command, type `/` and a list of all available commands is
shown above the command bar. Continue typing the command and git `Enter` to send the command.
You can send commands using the command bar. To send a command, type `/` and a list of all available commands is
shown above the command bar. Continue typing the command and hit `Enter` to send the command.

![Send command gif]()
![Send command gif](videos/cmds.gif)

The commands are loaded from a user YAML file, passed at start of program. An example of YAML file is shown below:
The commands are loaded from a user YAML file, passed at start of program (using `-c` flag). An example of YAML file is
shown below:

```yaml
hello: 'world!'
spaces: 'a big frase with spaces'
double_quotes: '"double"'
single_quotes: "'single'"
json: '{"cmd":1, "args":[true, "hello", 2.1]}'
hexa: !hex '5a a6 00 01'
json_again: '{"cmd":2, "args":"world"}'
```

### Written History

There is possible to retrieve old data and commands sent. You can hit `Up Arrow` and `Down Arrow` to navigate through
It's possible to retrieve old data and commands sent. You can hit `Up Arrow` and `Down Arrow` to navigate through
the history of sent data and commands.

![Command history]()
![Command history](videos/history.gif)

### Auto Reconnect

The scope has an auto-reconnect feature. When the serial port isn't available, the `Scope` stay trying to reconnect to
serial port, util it's available again.
The `Scope` tool has an auto-reconnect feature. When the serial port isn't available, `Scope` will keep trying to
reconnect to the serial port until it's available again.

![Reconnect gif]()
![Reconnect gif](videos/reconnect.gif)

### Colorful

The scope use color to transmit status of connection at the command bar (Red to disconnected and Green to connected).
Beyond status, the content read and write are colored too, to help understand. The value read is colored using ANSI
terminal color standard.
`Scope` colors the command bar to notify the status of the serial connection: red to disconnected and green to
connected. Beyond status, the content read and written are colored too. The messages read is colored using ANSI terminal
color standard.

![Read ANSI color gif]()
![Read ANSI color gif](videos/ansi.gif)

The data sent to serial port always been use background color to differentiate it from read data.
The data sent to serial port always has a background to differentiate it from read data. Characters outside the
printable range of the ASCII table are shown in magenta and in the hexadecimal format. Some characters are printed as
its representation, such as: `\n`, `\r` and `\0`.

![Write color gif]()
![Special character gif](videos/invisible.gif)

Characters outside the printable range of ASCII table are shown in magenta and in the hexadecimal format. Some
characters are printed as its representation, such as: '\n', '\r' and '\0'
### Message Timestamp

![Special character gif]()
All the data written or read has a gray timestamp on the left of the message and with the following
format: `HH:MM:SS.ms`.

### Message Timestamp
### Multiplatform

All the data written and read has a timestamp when its was sent or captured. This date is shown at left of the message,
in gray. It's having the total time, and the milliseconds after the dot.
You can use `Scope` on multiple platforms, like: Linux, Windows and macOS[^1].

![Timestamp gif]()
[^1]: Not tested yet.

### Multiplatform
### Plugins

You can extend the basic functions of `Scope` using plugins! Plugins are scripts written in `lua` language. To create a
plugin for `Scope` you'll need to write a lua script with these 2 functions: `serial_rx` and `user_command`.
The `serial_rx` function is called when a new data is captured on serial port. The `user_command` function is called
when you call your plugin from command bar, passing arguments to this command. The code bellow is a plugin to
reply `OK\r\n` when receive the `AT\r\n` message and to send `Hello, World\r\n` when the user type `!echo hello` on the
command bar.

```lua
require "scope"

function serial_rx(msg)
msg_str = bytes2str(msg)

You can use `Scope` on multiple platforms, like: Linux, Windows and macOS*.
if msg_str ~= "AT\r\n" then
return
end

*Not tested yet
scope.println("Sending msg \"OK\" via serial tx...")
scope.serial_tx(str2bytes("OK\r\n"))
scope.println("Message sent!")
end

function user_command(arg_list)
if arg_list[1] ~= "hello" then
return
end

scope.println("Hello, World!\r\n")
end
```

To call your plugin you need to type `!` followed by your plugin name and a list of arguments. Inside your plugin, is
possible to do many action to interact with `Scope` and serial port, such as: connect to a serial port, disconnect from
the serial port, send data to serial port, print some message in `Scope` text view and so on. For more information about
the development of plugins for `Scope` you can read
the [Plugins Developer Guide](https://github.com/matheuswhite/scope-rs/wiki/Plugin-Developer-Guide).

![Plugin usage](videos/plugin.gif)

## Scope vs Others

The `Scope` combine multiple fe
The `Scope` combine multiple features. The table below list these features:

| Features | Scope (Free) | Docklight | Arduino | Tera Term | screen | esp-idf |
|-----------------------------|--------------|-----------|---------|-----------|----------|----------|
| Send Data | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Send in Hexadecimal | ✅ | ✅ | x | x | x | x |
| Send Commands | ✅ | ✅ | x | x | x | x |
| Written History | ✅ | ✅* | x | x | x | x |
| Written History | ✅ | ✅[^2] | x | x | x | x |
| Auto Reconnect | ✅ | ✅ | x | ✅ | x | x |
| Colorful | ✅ | x | x | ✅ | ✅ | ✅ |
| Message Timestamp | ✅ | ✅ | x | x | x | x |
| Display non-printable chars | ✅ | ✅ | x | x | x | x |
| Multiplatform | ✅ | Windows | ✅ | Windows | Linux | ✅ |
| Multiplatform | ✅[^3] | Windows | ✅ | Windows | Linux | ✅ |
| Interface | TUI | GUI | GUI | GUI | Terminal | Terminal |
| Price | Free | €69 | Free | Free | Free | Free |

*The Docklight has a list of commands in lateral panel, so it doesn't need a command history
<br>[^2]: The Docklight has a list of commands in lateral panel, so it doesn't need a command history
<br>[^3]: Not tested on macOS yet

## Installation

You can use `cargo` to download and compile for your OS or download a pre-built binary at [Releases]() page
You can use `cargo` to install `Scope` or download a pre-built binary at [Releases]() page

### Using `cargo`

```shell
cargo install scope
```

## Getting Started
## How to Use

After the installation, type `scope serial` followed by the serial port and the desired baud rate. For example, to open
the port `ttyUSB0` at `115200bps` type:
After the installation, type `scope` followed by the serial port and the desired baud rate. For example, to open
the port `COM3` at `115200 bps` type:

```shell
scope serial /dev/ttyUSB0 115200
scope COM3 115200
```

When the command bar at bottom be green, you can start to capture and send messages via serial port.
When the command bar at the bottom is green, it starts to capture messages from serial port and allows for sending
messages.

To load a list of command, from a YAML file, use cloud type `-c <YOUR_COMMANDS>.yml` or `--cmd-file <YOUR_COMMANDS>.yml`
between `scope` and `serial`. For example, to load `cmd.yml` file, use can type:
To load a list of commands, from a YAML file, use should use `-c <YOUR_COMMANDS>.yml`
or `--cmd-file <YOUR_COMMANDS>.yml`
between `scope` and its parameters. For example, to load `cmd.yml` file, use can type:

```shell
scope -c cmd.yml serial /dev/ttyUSB0 115200
scope -c cmd.yml COM3 115200
```

or

```shell
scope --cmd-file serial /dev/ttyUSB0 115200
scope --cmd-file cmd.yml COM3 115200
```

To see the complete list of in-app features and how to use them, access [Usage Details]().

## Project Goals

This project has 4 pillars that will towards the development of this tool:

I. **Intuitive and Orthogonal Features:** The usage of the tool must be intuitive. This means implement the use of the
most established form, used in other tools. For example, the history navigation (`Up Arrow` and `Down Arrow`) follows
the history navigation of OS terminal like in the Unix shell and in the Windows Powershell.
<br>II. **User Centric Development:** New features must deliver value to user in first place, instead of please the
developers of this tool. For example, the script language used to extend the tool must be a consolidated programming
language, instead of creating a new language. Other example, it's prioritize critical bugs related by the users,
instead of launch new features.
<br>III. **Multiplatform:** All releases must work in Windows, Linux (zsh, shell and fish) and macOS.
<br>IV. **Extensible:** Support user scripts to extend the base functionalities

The roadmap, with next releases, cloud be found in [GitHub project](https://github.com/users/matheuswhite/projects/5)
This project has 5 pillars that will direct the development of this tool:

I. **Intuitive Usage:** The usage of the tool must be intuitive. This means the usability should follow other popular
tool's common behaviours. For example, the history navigation (`Up Arrow` and `Down Arrow`) follows the history
navigation of OS terminal like in the Unix shell and in the Windows Powershell.
<br>II. **Compactness and Orthogonality:** The features must follow
the [compactness and orthogonality](http://www.catb.org/esr/writings/taoup/html/ch04s02.html) principles of the Unix.
<br>III. **User Centric Development:** The development of this tool must deliver value to user in the first place,
instead of pleasing the developers. For example: the script language used to extend the tool must be a consolidated
programming language, instead of creating a new language. Another example is to prioritize critical bugs reported by
users, instead of launch new features.
<br>IV. **Multiplatform:** All releases must work in Windows, Linux (zsh, shell and fish) and macOS.
<br>V. **Extensible:** Support user scripts to extend base functionalities. These scripts are called plugins. For
more information about plugins
see [Plugins Developer Guide](https://github.com/matheuswhite/scope-rs/wiki/Plugin-Developer-Guide)

The roadmap, with next releases, may be found in [GitHub project](https://github.com/users/matheuswhite/projects/5)
of this tool.

## Community

For new feature request and relate a bug, feel free to post a
new [issues](https://github.com/matheuswhite/scope-rs/issues)
in GitHub.
For new feature requests and to report a bug, feel free to post a
new [issues](https://github.com/matheuswhite/scope-rs/issues) on GitHub.

## Contributing

Take a look at the [CONTRIBUTING]() guide
Take a look at the [CONTRIBUTING](CONTRIBUTING.md) guide

## Maintainers

+ [Matheus T. dos Santos](https://github.com/matheuswhite)

## Acknowledges

+ [Emilio Bottoni](https://github.com/MilhoNerfado) for be a heavy tester of this tool;
+ [Emilio Bottoni](https://github.com/MilhoNerfado) for being a heavy tester of this tool;
+ [José Gomes](https://github.com/JoseGomesJr) for some features and tests.

## License

Copyright (c) 2023 Matheus Tenório dos Santos

Scope is made available under the terms of BSD v3 Licence.

See the [LICENCE](https://github.com/matheuswhite/scope-rs/blob/main/LICENSE) for license details.
6 changes: 6 additions & 0 deletions cmd.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
hello: 'world!'
spaces: 'a big frase with spaces'
double_quotes: '"double"'
single_quotes: "'single'"
json: '{"cmd":1, "args":[true, "hello", 2.1]}'
json_again: '{"cmd":2, "args":"world"}'
7 changes: 5 additions & 2 deletions plugins/echo.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ function serial_rx(msg)
end

function user_command(arg_list)
scope.println("Hello! This is your echo:")
scope.println(arg_list[1])
if arg_list[1] ~= "hello" then
return
end

scope.println("Hello, World!\r\n")
end
24 changes: 24 additions & 0 deletions src/rich_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,23 +310,33 @@ impl RichTextAnsi {
let pattern_lut = HashMap::new()
.into_iter()
.chain([
(b"\x1B[m".to_vec(), (Color::Reset, Color::Reset)),
(b"\x1B[0m".to_vec(), (Color::Reset, Color::Reset)),
(b"\x1B[1m".to_vec(), (Color::Reset, Color::Reset)),
(b"\x1B[30m".to_vec(), (Color::Black, Color::Reset)),
(b"\x1B[0;30m".to_vec(), (Color::Black, Color::Reset)),
(b"\x1B[1;30m".to_vec(), (Color::Black, Color::Reset)),
(b"\x1B[31m".to_vec(), (Color::Red, Color::Reset)),
(b"\x1B[0;31m".to_vec(), (Color::Red, Color::Reset)),
(b"\x1B[1;31m".to_vec(), (Color::Red, Color::Reset)),
(b"\x1B[32m".to_vec(), (Color::Green, Color::Reset)),
(b"\x1B[0;32m".to_vec(), (Color::Green, Color::Reset)),
(b"\x1B[1;32m".to_vec(), (Color::Green, Color::Reset)),
(b"\x1B[33m".to_vec(), (Color::Yellow, Color::Reset)),
(b"\x1B[0;33m".to_vec(), (Color::Yellow, Color::Reset)),
(b"\x1B[1;33m".to_vec(), (Color::Yellow, Color::Reset)),
(b"\x1B[34m".to_vec(), (Color::Blue, Color::Reset)),
(b"\x1B[0;34m".to_vec(), (Color::Blue, Color::Reset)),
(b"\x1B[1;34m".to_vec(), (Color::Blue, Color::Reset)),
(b"\x1B[35m".to_vec(), (Color::Magenta, Color::Reset)),
(b"\x1B[0;35m".to_vec(), (Color::Magenta, Color::Reset)),
(b"\x1B[1;35m".to_vec(), (Color::Magenta, Color::Reset)),
(b"\x1B[36m".to_vec(), (Color::Cyan, Color::Reset)),
(b"\x1B[0;36m".to_vec(), (Color::Cyan, Color::Reset)),
(b"\x1B[1;36m".to_vec(), (Color::Cyan, Color::Reset)),
(b"\x1B[37m".to_vec(), (Color::Gray, Color::Reset)),
(b"\x1B[0;37m".to_vec(), (Color::Gray, Color::Reset)),
(b"\x1B[1;37m".to_vec(), (Color::Gray, Color::Reset)),
])
.collect::<HashMap<Vec<u8>, (Color, Color)>>();

Expand All @@ -338,6 +348,20 @@ impl RichTextAnsi {
return Ok(None);
}

if pattern.starts_with(b"\x1b[") && pattern[2..].iter().all(|x| x.is_ascii_digit()) {
return Ok(None);
}

if pattern == b"\x1b[J" {
return Ok(Some((Color::Reset, Color::Reset)));
}

if pattern.starts_with(b"\x1b[")
&& [b'A', b'B', b'C', b'D'].contains(pattern.last().unwrap())
{
return Ok(Some((Color::Reset, Color::Reset)));
}

Err(())
}
}
5 changes: 4 additions & 1 deletion src/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,10 @@ impl SerialIF {
}
}
Err(ref e) if e.kind() == io::ErrorKind::TimedOut => {}
Err(ref e) if e.kind() == io::ErrorKind::PermissionDenied => {
Err(ref e)
if e.kind() == io::ErrorKind::PermissionDenied
|| e.kind() == io::ErrorKind::BrokenPipe =>
{
is_connected.store(false, Ordering::SeqCst);
serial = SerialIF::reconnect(
port,
Expand Down
Loading
Loading