Added size suffixes
This commit is contained in:
160
README.md
160
README.md
@@ -4,7 +4,7 @@ This is a C equivalent of the Python `main.py` script for reading data from True
|
|||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
The program reads random data from a TrueRNG device via serial port, counts the number of ones and zeros in the data, and saves the raw data to a binary file called `random.bin`.
|
The program reads random data from a TrueRNG device via serial port, counts the number of ones and zeros in the data, and provides flexible output options including multiple formats and size specifications.
|
||||||
|
|
||||||
## Supported Devices
|
## Supported Devices
|
||||||
|
|
||||||
@@ -32,24 +32,83 @@ gcc -Wall -Wextra -std=c99 -O2 -o truerng main.c
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
### Basic Usage
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./truerng
|
./truerng
|
||||||
```
|
```
|
||||||
|
|
||||||
The program will:
|
### Command Line Options
|
||||||
1. Automatically detect connected TrueRNG devices
|
|
||||||
2. Read 1024 blocks of 1024 bytes each (1MB total)
|
```bash
|
||||||
3. Count ones and zeros in real-time
|
./truerng [OPTIONS]
|
||||||
4. Display read rate in KB/s
|
```
|
||||||
5. Save raw data to `random.bin`
|
|
||||||
6. Display final statistics
|
**Options:**
|
||||||
|
- `-n, --bytes <N>` - Number of bytes to generate (default: 1048576)
|
||||||
|
- Supports size suffixes: K, MB, GB, TB (case-insensitive)
|
||||||
|
- Examples: `1024`, `1K`, `2.5MB`, `1GB`, `512k`, `1tb`
|
||||||
|
- `-f, --format <FORMAT>` - Output format: binary, hex, base64, decimal
|
||||||
|
- Default: binary when piped, hex in interactive mode
|
||||||
|
- `-o, --output <FILE>` - Output filename (works with all formats)
|
||||||
|
- `-q, --quiet` - Suppress statistics/progress output
|
||||||
|
- `-v, --verbose` - Show detailed device information
|
||||||
|
- `-h, --help` - Show help message
|
||||||
|
|
||||||
|
### Size Suffixes
|
||||||
|
|
||||||
|
The `-n` option supports convenient size suffixes (case-insensitive):
|
||||||
|
- **K** or **KB**: Kilobytes (1024 bytes)
|
||||||
|
- **M** or **MB**: Megabytes (1,048,576 bytes)
|
||||||
|
- **G** or **GB**: Gigabytes (1,073,741,824 bytes)
|
||||||
|
- **T** or **TB**: Terabytes (1,099,511,627,776 bytes)
|
||||||
|
|
||||||
|
Decimal values are supported: `1.5MB`, `2.5GB`, etc.
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Basic usage - interactive mode with hex output
|
||||||
|
./truerng
|
||||||
|
|
||||||
|
# Generate 1KB of data in hex format
|
||||||
|
./truerng -n 1K -f hex
|
||||||
|
|
||||||
|
# Generate 2.5MB and pipe to another program
|
||||||
|
./truerng -n 2.5MB | xxd
|
||||||
|
|
||||||
|
# Save 1GB of binary data to file quietly
|
||||||
|
./truerng -n 1GB -o random.dat -q
|
||||||
|
|
||||||
|
# Generate 512KB as hex and save to file
|
||||||
|
./truerng -n 512K -f hex -o output.hex
|
||||||
|
|
||||||
|
# Generate base64 output with verbose device info
|
||||||
|
./truerng -n 1MB -f base64 -v
|
||||||
|
|
||||||
|
# Backward compatibility - plain numbers still work
|
||||||
|
./truerng -n 1048576 -f binary
|
||||||
|
```
|
||||||
|
|
||||||
|
### Output Formats
|
||||||
|
|
||||||
|
- **binary**: Raw binary data (default for piped output)
|
||||||
|
- **hex**: Hexadecimal representation (default for interactive mode)
|
||||||
|
- **base64**: Base64 encoded output
|
||||||
|
- **decimal**: Decimal byte values
|
||||||
|
|
||||||
|
### Modes
|
||||||
|
|
||||||
|
The program automatically detects the execution context:
|
||||||
|
- **Interactive mode**: Shows progress, statistics, and defaults to hex output
|
||||||
|
- **Piped mode**: Optimized for piping, defaults to binary output
|
||||||
|
- **File output**: Can be combined with any format using `-o` option
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
You can modify the following constants in [`main.c`](main.c:32):
|
You can modify the following constants in [`main.c`](main.c:34):
|
||||||
|
|
||||||
- `BLOCKSIZE`: Number of bytes to read per block (default: 1024)
|
- `BLOCKSIZE`: Number of bytes to read per block (default: 1024)
|
||||||
- `NUMLOOPS`: Number of blocks to read (default: 1024)
|
|
||||||
|
|
||||||
## Permissions
|
## Permissions
|
||||||
|
|
||||||
@@ -70,30 +129,77 @@ The C implementation:
|
|||||||
- Uses native Linux serial port APIs instead of pyserial
|
- Uses native Linux serial port APIs instead of pyserial
|
||||||
- Implements USB device detection via sysfs
|
- Implements USB device detection via sysfs
|
||||||
- Uses lookup tables for efficient bit counting
|
- Uses lookup tables for efficient bit counting
|
||||||
|
- Provides enhanced command line interface with size suffixes
|
||||||
|
- Supports multiple output formats (binary, hex, base64, decimal)
|
||||||
- Provides equivalent functionality with better performance
|
- Provides equivalent functionality with better performance
|
||||||
|
|
||||||
## Output
|
## Sample Output
|
||||||
|
|
||||||
Sample output:
|
### Interactive Mode
|
||||||
```
|
```
|
||||||
TrueRNG Counting Ones vs Zeros Example
|
TrueRNG - True Random Number Generator
|
||||||
http://ubld.it
|
|
||||||
==================================================
|
==================================================
|
||||||
TrueRNG Found
|
TrueRNGproV2 Found
|
||||||
Using com port: /dev/ttyUSB0
|
Using port: /dev/ttyACM0
|
||||||
Block Size: 1024 Bytes
|
Generating: 1024 bytes
|
||||||
Number of loops: 1024
|
Starting data collection...
|
||||||
Total size: 1048576 Bytes
|
1024/1024 Bytes Read at 504.19 Kbytes/s
|
||||||
Writing to: random.bin
|
|
||||||
==================================================
|
|
||||||
1048576 Bytes Read at 45.23 Kbytes/s
|
|
||||||
|
|
||||||
Results
|
Results
|
||||||
=======
|
=======
|
||||||
Total Ones : 4194234
|
Total time: 0.02 seconds
|
||||||
Total Zeros: 4194314
|
Total Ones: 4072
|
||||||
|
Total Zeros: 4120
|
||||||
|
Total Bits: 8192
|
||||||
|
Extra zeros: 48
|
||||||
|
=======
|
||||||
|
```
|
||||||
|
|
||||||
Total Bits : 8388608
|
### Piped Mode with Verbose
|
||||||
|
```
|
||||||
|
TrueRNG - True Random Number Generator
|
||||||
|
Mode: Piped (Verbose)
|
||||||
|
==================================================
|
||||||
|
TrueRNGproV2 Found
|
||||||
|
Using port: /dev/ttyACM0
|
||||||
|
Generating: 2048 bytes
|
||||||
|
Starting data collection...
|
||||||
|
2048/2048 Bytes Read at 462.17 Kbytes/s
|
||||||
|
|
||||||
There are 80 more zeros in the Capture!
|
Results
|
||||||
=======
|
=======
|
||||||
|
Total time: 0.04 seconds
|
||||||
|
Total Ones: 8144
|
||||||
|
Total Zeros: 8248
|
||||||
|
Total Bits: 16392
|
||||||
|
Extra zeros: 104
|
||||||
|
=======
|
||||||
|
```
|
||||||
|
|
||||||
|
### Quiet Mode
|
||||||
|
```bash
|
||||||
|
./truerng -n 1K -o data.bin -q
|
||||||
|
# No output - data saved silently to data.bin
|
||||||
|
```
|
||||||
|
|
||||||
|
### Help Output
|
||||||
|
```bash
|
||||||
|
./truerng --help
|
||||||
|
TrueRNG - True Random Number Generator
|
||||||
|
Usage: truerng [OPTIONS]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-n, --bytes <N> Number of bytes to generate (default: 1048576)
|
||||||
|
Supports suffixes: K, MB, GB, TB (e.g., 1K, 2.5MB, 1GB)
|
||||||
|
-f, --format <FORMAT> Output format: binary, hex, base64, decimal (default: binary when piped, interactive otherwise)
|
||||||
|
-o, --output <FILE> Output filename (ignored in piped mode)
|
||||||
|
-q, --quiet Suppress statistics/progress
|
||||||
|
-v, --verbose Show detailed device information
|
||||||
|
-h, --help Show this help message
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
truerng -n 1024 -f hex # Interactive mode with hex output
|
||||||
|
truerng -n 1K -f hex # Same as above using K suffix
|
||||||
|
truerng -n 2.5MB | xxd # Piped mode with MB suffix
|
||||||
|
truerng -n 1GB -o random.dat -q # Save 1GB to file quietly
|
||||||
|
truerng -n 512K -f hex -o output.hex # Save 512KB as hex to file
|
||||||
84
main.c
84
main.c
@@ -24,6 +24,7 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
// Define CRTSCTS if not available
|
// Define CRTSCTS if not available
|
||||||
#ifndef CRTSCTS
|
#ifndef CRTSCTS
|
||||||
@@ -63,12 +64,71 @@ struct Options options;
|
|||||||
// Global variables
|
// Global variables
|
||||||
static int ones_in_byte[256];
|
static int ones_in_byte[256];
|
||||||
|
|
||||||
|
// Parse byte size with optional suffix (K, MB, GB, TB)
|
||||||
|
// Returns: parsed size in bytes, or -1 on error
|
||||||
|
// Sets *error to 1 if parsing fails, 0 on success
|
||||||
|
long long parse_byte_size(const char* size_str, int* error) {
|
||||||
|
if (!size_str || !error) {
|
||||||
|
if (error) *error = 1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*error = 0;
|
||||||
|
char* endptr;
|
||||||
|
double value = strtod(size_str, &endptr);
|
||||||
|
|
||||||
|
if (value < 0) {
|
||||||
|
*error = 1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no suffix, return the value as bytes (backward compatibility)
|
||||||
|
if (*endptr == '\0') {
|
||||||
|
if (value > LLONG_MAX) {
|
||||||
|
*error = 1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return (long long)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse suffix (case-insensitive)
|
||||||
|
char suffix[4] = {0};
|
||||||
|
int i = 0;
|
||||||
|
while (*endptr && i < 3) {
|
||||||
|
suffix[i++] = toupper(*endptr++);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine multiplier
|
||||||
|
long long multiplier = 1;
|
||||||
|
if (strcmp(suffix, "K") == 0 || strcmp(suffix, "KB") == 0) {
|
||||||
|
multiplier = 1024LL;
|
||||||
|
} else if (strcmp(suffix, "M") == 0 || strcmp(suffix, "MB") == 0) {
|
||||||
|
multiplier = 1024LL * 1024LL;
|
||||||
|
} else if (strcmp(suffix, "G") == 0 || strcmp(suffix, "GB") == 0) {
|
||||||
|
multiplier = 1024LL * 1024LL * 1024LL;
|
||||||
|
} else if (strcmp(suffix, "T") == 0 || strcmp(suffix, "TB") == 0) {
|
||||||
|
multiplier = 1024LL * 1024LL * 1024LL * 1024LL;
|
||||||
|
} else {
|
||||||
|
*error = 1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for overflow
|
||||||
|
if (value > (double)LLONG_MAX / multiplier) {
|
||||||
|
*error = 1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (long long)(value * multiplier);
|
||||||
|
}
|
||||||
|
|
||||||
// Output format functions
|
// Output format functions
|
||||||
void output_binary(unsigned char *buffer, int bytes_read, FILE *out) {
|
void output_binary(unsigned char *buffer, int bytes_read, FILE *out) {
|
||||||
fwrite(buffer, 1, bytes_read, out);
|
fwrite(buffer, 1, bytes_read, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
void output_hex(unsigned char *buffer, int bytes_read, FILE *out, int piped) {
|
void output_hex(unsigned char *buffer, int bytes_read, FILE *out, int piped) {
|
||||||
|
(void)piped; // Suppress unused parameter warning
|
||||||
for (int i = 0; i < bytes_read; i++) {
|
for (int i = 0; i < bytes_read; i++) {
|
||||||
fprintf(out, "%02x", buffer[i]);
|
fprintf(out, "%02x", buffer[i]);
|
||||||
}
|
}
|
||||||
@@ -77,6 +137,7 @@ void output_hex(unsigned char *buffer, int bytes_read, FILE *out, int piped) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void output_decimal(unsigned char *buffer, int bytes_read, FILE *out, int piped) {
|
void output_decimal(unsigned char *buffer, int bytes_read, FILE *out, int piped) {
|
||||||
|
(void)piped; // Suppress unused parameter warning
|
||||||
for (int i = 0; i < bytes_read; i++) {
|
for (int i = 0; i < bytes_read; i++) {
|
||||||
fprintf(out, "%d", buffer[i]);
|
fprintf(out, "%d", buffer[i]);
|
||||||
}
|
}
|
||||||
@@ -85,6 +146,7 @@ void output_decimal(unsigned char *buffer, int bytes_read, FILE *out, int piped)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void output_base64(unsigned char *buffer, int bytes_read, FILE *out, int piped) {
|
void output_base64(unsigned char *buffer, int bytes_read, FILE *out, int piped) {
|
||||||
|
(void)piped; // Suppress unused parameter warning
|
||||||
static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
char encoded[5];
|
char encoded[5];
|
||||||
for (int i = 0; i < bytes_read; i += 3) {
|
for (int i = 0; i < bytes_read; i += 3) {
|
||||||
@@ -118,6 +180,7 @@ void print_usage(void) {
|
|||||||
printf("Usage: truerng [OPTIONS]\n\n");
|
printf("Usage: truerng [OPTIONS]\n\n");
|
||||||
printf("Options:\n");
|
printf("Options:\n");
|
||||||
printf(" -n, --bytes <N> Number of bytes to generate (default: 1048576)\n");
|
printf(" -n, --bytes <N> Number of bytes to generate (default: 1048576)\n");
|
||||||
|
printf(" Supports suffixes: K, MB, GB, TB (e.g., 1K, 2.5MB, 1GB)\n");
|
||||||
printf(" -f, --format <FORMAT> Output format: binary, hex, base64, decimal (default: binary when piped, interactive otherwise)\n");
|
printf(" -f, --format <FORMAT> Output format: binary, hex, base64, decimal (default: binary when piped, interactive otherwise)\n");
|
||||||
printf(" -o, --output <FILE> Output filename (ignored in piped mode)\n");
|
printf(" -o, --output <FILE> Output filename (ignored in piped mode)\n");
|
||||||
printf(" -q, --quiet Suppress statistics/progress\n");
|
printf(" -q, --quiet Suppress statistics/progress\n");
|
||||||
@@ -125,8 +188,10 @@ void print_usage(void) {
|
|||||||
printf(" -h, --help Show this help message\n");
|
printf(" -h, --help Show this help message\n");
|
||||||
printf("\nExamples:\n");
|
printf("\nExamples:\n");
|
||||||
printf(" truerng -n 1024 -f hex # Interactive mode with hex output\n");
|
printf(" truerng -n 1024 -f hex # Interactive mode with hex output\n");
|
||||||
printf(" truerng -n 1024 | xxd # Piped mode to hex viewer\n");
|
printf(" truerng -n 1K -f hex # Same as above using K suffix\n");
|
||||||
printf(" truerng -o random.dat -q # Save to file quietly\n");
|
printf(" truerng -n 2.5MB | xxd # Piped mode with MB suffix\n");
|
||||||
|
printf(" truerng -n 1GB -o random.dat -q # Save 1GB to file quietly\n");
|
||||||
|
printf(" truerng -n 512K -f hex -o output.hex # Save 512KB as hex to file\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int parse_arguments(int argc, char *argv[]) {
|
int parse_arguments(int argc, char *argv[]) {
|
||||||
@@ -152,13 +217,15 @@ int parse_arguments(int argc, char *argv[]) {
|
|||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
while ((opt = getopt_long(argc, argv, opt_string, long_options, &option_index)) != -1) {
|
while ((opt = getopt_long(argc, argv, opt_string, long_options, &option_index)) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'n':
|
case 'n': {
|
||||||
options.bytes = atol(optarg);
|
int parse_error;
|
||||||
if (options.bytes <= 0) {
|
options.bytes = parse_byte_size(optarg, &parse_error);
|
||||||
fprintf(stderr, "Error: Bytes must be positive\n");
|
if (parse_error || options.bytes <= 0) {
|
||||||
|
fprintf(stderr, "Error: Invalid byte size '%s'. Use a positive number optionally followed by K, MB, GB, or TB\n", optarg);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 'f':
|
case 'f':
|
||||||
if (strcmp(optarg, "binary") == 0) options.format = BINARY;
|
if (strcmp(optarg, "binary") == 0) options.format = BINARY;
|
||||||
else if (strcmp(optarg, "hex") == 0) options.format = HEX;
|
else if (strcmp(optarg, "hex") == 0) options.format = HEX;
|
||||||
@@ -199,6 +266,7 @@ int find_truerng_port(char* port_path, int piped, int verbose);
|
|||||||
int setup_serial_port(const char* port_path);
|
int setup_serial_port(const char* port_path);
|
||||||
int read_usb_device_info(const char* port_name, char* vid, char* pid);
|
int read_usb_device_info(const char* port_name, char* vid, char* pid);
|
||||||
double get_time_diff(struct timeval start, struct timeval end);
|
double get_time_diff(struct timeval start, struct timeval end);
|
||||||
|
long long parse_byte_size(const char* size_str, int* error);
|
||||||
int parse_arguments(int argc, char *argv[]);
|
int parse_arguments(int argc, char *argv[]);
|
||||||
void print_usage(void);
|
void print_usage(void);
|
||||||
int is_piped(void);
|
int is_piped(void);
|
||||||
@@ -573,7 +641,9 @@ cleanup:
|
|||||||
// Reset terminal min setting
|
// Reset terminal min setting
|
||||||
char stty_cmd[MAX_PATH + 20];
|
char stty_cmd[MAX_PATH + 20];
|
||||||
snprintf(stty_cmd, sizeof(stty_cmd), "stty -F %s min 1", port_path);
|
snprintf(stty_cmd, sizeof(stty_cmd), "stty -F %s min 1", port_path);
|
||||||
system(stty_cmd); // Ignore failure
|
if (system(stty_cmd) != 0) {
|
||||||
|
// Ignore failure - this is just cleanup
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1 +0,0 @@
|
|||||||
6b5a1ff13961684786b40997b5d4fe5ff573b9fadf6ea798911ba5d628129501078309b22a0ccfd8c34035e2a7574d7aa94b28fc155d8d19d7164bb68a4bba4d95a6809a08c9cbd698792a49c66cbad2603222523a48eda4f3a726b2b331063a1af6fb9fe2cd4d4a81231096046e185839c6ae4f542fc51f81fee77277f906dcf031014228719589e1c09647a6909bcf6770b6cd66559356858f1b31b338b0f894de5ddfc1048c7bd38faf31b83649dbdc5fdf70b4a980b01c0860df564d615500f0d35454a4c7b1d249f368558a7ecdbb7a7036899ad305bc6b6ee5c11eac0b6890d0e82f5c5f7af765d0b159901972dd8cd6a99013868b82b3e816b62b1abd996a6d7167f8441bc6319189968df6e0e106425ed9502fbaa3caeba77971c9f8853072436ba8e5ffb3ff0db175c0d1bec45eb435b23bf0310a9a466b3f9a50675520b75bfc32d2adb3713f2e1b449e4c9a20a3ed960e5a473f9535b0ab2fc490f1d47bf853ca64512ddf520ef3ab4fa45cda19f70adc21344e3fa56693c4c04ebb0684ef0fcf431a28105c417f33c9f6f7a3f941becd61df8b2e4a73268d5df67d86b2a074d37c0c5ef8a16d11542a260341e407fc026a27b5defbd6cd9503c46fde1e140555da641e5157816d9075a6cb0543eaa039388e9fa4640f32e818b3cebf3a218b3cbfb1133690b9b49b0080da077312b6670309d0d616717d5638c68eea3db0c31e3c448bfa027c8e52a37bf3c0dad2152904263510a25af39db48326fd7a731ce105588b2dc26e9bf9229fc71a1587800740a598e6d842aa5e76c62acf88d481bc2bd9ede29fc05f03787afbb7cf9c030c896797c7bfa6b43a6b54b76c661146e78bc214a28459f94d4bc43bbfdaf74f665252370e0c51c438d94437e4cdbe26ce469d8e5ea2eec00ca6aae65b4a6e683d3cfd6d53b6bca388318b6228731dfc6c9a376a7277b8b73e26d9d8a892def68f248949576b1c4aedf6cd404c88191b4335993ad995a87f11490003271404ed58543bbf74123e8d2a23b09655720b79cfbf62dd2f7f8e1463da65034c429a637dcdfcebc8f08764c4ea612c40f62d6ce2b0eae6a42caf5d620bdef28450325370e159cb58b7554fc6d7ea2e10e2c24d378ab536fd71deafa10177683c0644343f1410a388606aad7550f505c45261d5bda7e5a3902a75ffd476b013960676e16b9780b8086dd6b5795dfb37926e023a00b6911513dacb5e2a8f019a8f1c115e840a4e2c6f103d1458270135fccab4205e3101debf84a5127ebc31b03a4eb4c2e14fa07baea02f40f7b021606c8af0789156b19818bc47a521ca3107c9b1cc78c8f0151c6b730013dbd1a3049f2ed38fe6aebbf601a633dfdd21ddae0f018c6ab6b724a21da6e95e7f3e3ba5ba84650cfbb4821707d524882665068464bdd83ad7a91442b35a01ee7651aa
|
|
||||||
1024
test_output.txt
1024
test_output.txt
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user