phase 1: cleanup, REPL polish, README
- fix format-string in jprint/script_print (printf(msg) -> fputs)
- fix bsexp_deinit: deinit_script guarded by sctx, not jc
- silence "config.script not found" when the optional override is absent
- remove dead code: bs/cmds/, bs/args.{c,h}, bs/utils.h, commented blocks
- REPL: welcome banner with version, readline tab-completion on
script_commands_list, skip blank lines, clean Ctrl-D exit
- README: build, REPL usage, typical SPI flow, command table, probes,
Xilinx STARTUPE3/CCLK caveat
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
135
README.md
135
README.md
@@ -1,16 +1,135 @@
|
|||||||
# My application for boundary scan
|
# bs_explorer — Boundary Scan Explorer
|
||||||
|
|
||||||
Basée sur la librairie de l'application [jtag-boundary-scanner](https://github.com/viveris/jtag-boundary-scanner).
|
Outil en ligne de commande pour explorer une chaîne JTAG, contrôler les
|
||||||
|
broches d'un FPGA via le boundary scan (BSDL), et — à terme — programmer
|
||||||
|
les mémoires SPI connectées au FPGA (Xilinx et autres) en bit-bangeant
|
||||||
|
SPI sur les pins d'I/O placés en EXTEST.
|
||||||
|
|
||||||
## Usage
|
Basé sur la librairie [jtag-boundary-scanner](https://github.com/viveris/jtag-boundary-scanner)
|
||||||
|
de Viveris (LGPL).
|
||||||
|
|
||||||
TBD
|
## État
|
||||||
|
|
||||||
## How to compile
|
- Détection de la chaîne JTAG via sondes FTDI / J-Link / Linux GPIO : OK
|
||||||
|
- Chargement automatique d'un BSDL par IDCODE : OK
|
||||||
|
- Pilotage de pins en SAMPLE / EXTEST : OK
|
||||||
|
- SPI bit-bang sur 4 pins du FPGA (MOSI/MISO/CS/CLK) : OK (primitive bas niveau)
|
||||||
|
- Programmation de flash SPI (détection JEDEC, erase, page program, verify) : **à venir**
|
||||||
|
- Abstraction multi-FPGA (mapping pins → flash par cible) : **à venir**
|
||||||
|
|
||||||
```
|
Seul BSDL embarqué pour l'instant : Xilinx Kintex UltraScale+ KU15P
|
||||||
mkdir build
|
(`bsdl_files/xcku15p_ffve1517.bsd`). En ajouter d'autres se fait en
|
||||||
cd build
|
déposant le `.bsd` dans `bsdl_files/`.
|
||||||
|
|
||||||
|
## Dépendances
|
||||||
|
|
||||||
|
- CMake ≥ 3.10, gcc/clang
|
||||||
|
- `readline` (Arch : `readline`, Debian/Ubuntu : `libreadline-dev`)
|
||||||
|
- `libftd2xx` pour les sondes FTDI (vendoré dans `libs/libftd2xx/`)
|
||||||
|
|
||||||
|
## Compilation
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mkdir build && cd build
|
||||||
cmake ..
|
cmake ..
|
||||||
make
|
make
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Le binaire est produit dans `build/bs/bs`.
|
||||||
|
|
||||||
|
## Lancement
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cd build
|
||||||
|
./bs/bs
|
||||||
|
```
|
||||||
|
|
||||||
|
Au démarrage, `bs_explorer` cherche un fichier `config.script` dans le
|
||||||
|
répertoire courant pour surcharger les variables par défaut (clock FTDI,
|
||||||
|
mapping des broches TRST/SRST, etc.). Voir `modules/config/config.script`
|
||||||
|
pour la liste des variables disponibles.
|
||||||
|
|
||||||
|
## REPL
|
||||||
|
|
||||||
|
- `<Tab>` complète les noms de commande.
|
||||||
|
- Historique géré par GNU readline (flèches haut/bas, Ctrl-R…).
|
||||||
|
- `help` ou `?` liste les commandes ; `help <cmd>` détaille une commande.
|
||||||
|
- `exit`, `quit` ou Ctrl-D pour quitter.
|
||||||
|
|
||||||
|
## Flow typique
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# 1. Ouvrir une sonde (1 = première sonde détectée)
|
||||||
|
bs_explorer> jtag_get_probes_list
|
||||||
|
bs_explorer> jtag_open_probe 1
|
||||||
|
|
||||||
|
# 2. Scanner la chaîne et charger les BSDL automatiquement
|
||||||
|
bs_explorer> jtag_autoinit
|
||||||
|
|
||||||
|
# 3. Passer le device 0 en EXTEST (contrôle direct des broches)
|
||||||
|
bs_explorer> jtag_set_mode 0 EXTEST
|
||||||
|
|
||||||
|
# 4. Configurer les 4 pins SPI sur les broches BSDL du FPGA
|
||||||
|
# (les noms exacts dépendent du BSDL chargé)
|
||||||
|
bs_explorer> jtag_set_spi_cs_pin 0 <PIN_CS> 0
|
||||||
|
bs_explorer> jtag_set_spi_clk_pin 0 <PIN_CLK> 0
|
||||||
|
bs_explorer> jtag_set_spi_mosi_pin 0 <PIN_MOSI> 0
|
||||||
|
bs_explorer> jtag_set_spi_miso_pin 0 <PIN_MISO> 0
|
||||||
|
|
||||||
|
# 5. Lire le JEDEC ID de la flash (0x9F + 3 dummies)
|
||||||
|
bs_explorer> jtag_spi_rd_wr 9F000000
|
||||||
|
```
|
||||||
|
|
||||||
|
Un fichier d'exemple minimal est fourni dans `scripts/example_script.txt`.
|
||||||
|
|
||||||
|
## Commandes principales
|
||||||
|
|
||||||
|
| Catégorie | Commandes |
|
||||||
|
|---------------|-----------|
|
||||||
|
| Contrôle script | `set`, `print`, `print_env_var`, `if`, `goto`, `call`, `return`, `rand`, `init_array`, `system`, `pause` |
|
||||||
|
| Sonde / chaîne | `jtag_get_probes_list`, `jtag_open_probe`, `jtag_init_scan`, `jtag_autoinit`, `jtag_get_nb_of_devices`, `jtag_get_devices_list` |
|
||||||
|
| BSDL / pins | `jtag_load_bsdl`, `jtag_get_pins_list`, `jtag_set_mode`, `jtag_set_pin_dir`, `jtag_set_pin_state`, `jtag_get_pin_state`, `jtag_push_pop` |
|
||||||
|
| I²C / MDIO / SPI sur pins BS | `jtag_set_i2c_*_pin`, `jtag_i2c_rd`, `jtag_i2c_wr`, `jtag_set_mdio_*_pin`, `jtag_mdio_rd`, `jtag_mdio_wr`, `jtag_set_spi_*_pin`, `jtag_spi_rd_wr` |
|
||||||
|
| Misc | `help`, `?`, `version`, `exit` |
|
||||||
|
|
||||||
|
Utiliser `help <commande>` pour l'aide détaillée.
|
||||||
|
|
||||||
|
## Sondes supportées
|
||||||
|
|
||||||
|
- **FTDI** MPSSE (FT2232D/H, FT4232H…) — voir le bloc `PROBE_FTDI_*` dans
|
||||||
|
`modules/config/config.script` pour le mapping des broches et la fréquence TCK.
|
||||||
|
- **SEGGER J-Link**
|
||||||
|
- **Linux GPIO** (sysfs ; déprécié sur kernels récents, à migrer vers libgpiod)
|
||||||
|
|
||||||
|
## Limitations connues sur Xilinx
|
||||||
|
|
||||||
|
Sur 7-Series / UltraScale / UltraScale+, `CCLK` n'est pas une broche
|
||||||
|
d'I/O classique et passe par la primitive `STARTUPE3`. Elle n'est donc
|
||||||
|
pas directement pilotable en EXTEST. Workarounds connus :
|
||||||
|
- utiliser l'instruction privée `ISC_DISABLE` ;
|
||||||
|
- câbler l'horloge SPI sur un autre pin utilisateur du FPGA.
|
||||||
|
|
||||||
|
À traiter lors de l'ajout de la couche d'abstraction FPGA.
|
||||||
|
|
||||||
|
## Structure du dépôt
|
||||||
|
|
||||||
|
```
|
||||||
|
bs/ Application (REPL readline)
|
||||||
|
modules/
|
||||||
|
├── jtag_core/ TAP state machine, IR/DR shifts
|
||||||
|
├── bsdl_parser/ Chargement de .bsd
|
||||||
|
├── bus_over_jtag/ SPI / I²C / MDIO / mem parallèle bit-bangés
|
||||||
|
├── drivers/ FTDI, J-Link, Linux GPIO, LPT
|
||||||
|
├── script/ Moteur de scripts (40+ commandes)
|
||||||
|
├── config/ config.script intégré
|
||||||
|
├── os_interface/ Wrappers fs/network portables
|
||||||
|
└── natsort/ Tri naturel des noms de pin
|
||||||
|
bsdl_files/ Fichiers BSDL des FPGAs cibles
|
||||||
|
scripts/ Exemples de scripts
|
||||||
|
libs/libftd2xx/ SDK FTDI vendoré
|
||||||
|
```
|
||||||
|
|
||||||
|
## Licence
|
||||||
|
|
||||||
|
`modules/jtag_core/` et les fichiers d'origine Viveris sont sous LGPL 2.1.
|
||||||
|
Voir `LICENSE` et `modules/jtag_core/COPYING.LESSER`.
|
||||||
|
|||||||
91
bs/args.c
91
bs/args.c
@@ -1,91 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <getopt.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "args.h"
|
|
||||||
|
|
||||||
// void global_help() {
|
|
||||||
// printf("Usage: bs [[-l] [--list]] [[-n] [--nprobe]] [[-b] [--bsdl]] [[-d] [--device_id]] PROBE_NUM] [<cmd>] [<cmd_options>]\n");
|
|
||||||
// }
|
|
||||||
|
|
||||||
// int parse_args(struct args *a, int argc, char *argv[]) {
|
|
||||||
// int opt = 0;
|
|
||||||
// int i = 0;
|
|
||||||
// unsigned int devid = 0;
|
|
||||||
// int command = 0;
|
|
||||||
// __uint8_t option_arg[MAX_PATH] = {0};
|
|
||||||
|
|
||||||
// // Définir les options longues
|
|
||||||
// static struct option long_options[] = {
|
|
||||||
// {"list", no_argument, 0, 'l'},
|
|
||||||
// {"nprobe", required_argument, 0, 'n'},
|
|
||||||
// {"bsdl", required_argument, 0, 'b'},
|
|
||||||
// {"device_id", required_argument, 0, 'd'},
|
|
||||||
// {0, 0, 0, 0}
|
|
||||||
// };
|
|
||||||
|
|
||||||
// // Utilisation de getopt_long pour parser les options
|
|
||||||
// while ((opt = getopt_long(argc, argv, "ln:b:d:", long_options, NULL)) != -1) {
|
|
||||||
// switch (opt) {
|
|
||||||
// case 'h':
|
|
||||||
// a->list = 1;
|
|
||||||
// break;
|
|
||||||
// case 'n':
|
|
||||||
// snprintf(option_arg, sizeof(option_arg)-2, "%s", optarg);
|
|
||||||
// a->probe = atoi(option_arg);
|
|
||||||
// break;
|
|
||||||
// case 'b':
|
|
||||||
// snprintf(a->bsdl, MAX_PATH-2, "%s", optarg);
|
|
||||||
// break;
|
|
||||||
// case 'd':
|
|
||||||
// i = sscanf(optarg, "0x%x", &devid);
|
|
||||||
// if (i == 0) {
|
|
||||||
// printf("Device ID must be an hex value like '0xABCD'");
|
|
||||||
// return EXIT_FAILURE;
|
|
||||||
// }
|
|
||||||
// break;
|
|
||||||
// default:
|
|
||||||
// usage();
|
|
||||||
// return EXIT_FAILURE;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Positional arguments
|
|
||||||
// if (optind < argc) {
|
|
||||||
// /* Positional arguments */
|
|
||||||
// while (optind < argc) {
|
|
||||||
// for (i=0;i<COMMANDS_NUMBER-1;i++) {
|
|
||||||
// if (0 == strcmp(COMMAND_STRINGS[i], argv[optind])) {
|
|
||||||
// a->cmds[command] = (enum commands)i+1;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// optind++;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Si aucune option n'est fournie, afficher l'aide
|
|
||||||
// if (optind == 1) {
|
|
||||||
// usage();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return EXIT_SUCCESS;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// void parse_command(char *line, int *argc, char **argv) {
|
|
||||||
// *argc = 0;
|
|
||||||
// while (*line != '\0') {
|
|
||||||
// while (*line == ' ' || *line == '\t' || *line == '\n') {
|
|
||||||
// *line++ = '\0';
|
|
||||||
// }
|
|
||||||
// if (*argc >= MAX_ARGS) break;
|
|
||||||
// (*argc)++;
|
|
||||||
// *argv++ = line;
|
|
||||||
// while (*line != '\0' && *line != ' ' && *line != '\t' && *line != '\n') {
|
|
||||||
// line++;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// *argv = '\0';
|
|
||||||
// }
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#ifndef _ARGS_H
|
|
||||||
#define _ARGS_H
|
|
||||||
|
|
||||||
// int parse_args(struct args *a, int argc, char *argv[]);
|
|
||||||
// void parse_command(char *line, int *argc, char **argv);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "exit.h"
|
|
||||||
|
|
||||||
const char cmd_exit_help[] = "Bla bla.";
|
|
||||||
|
|
||||||
int cmd_exit(jtag_core *jc, int argc, char **argv) {
|
|
||||||
jtagcore_deinit(jc);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#ifndef _CMD_EXIT_H
|
|
||||||
#define _CMD_EXIT_H
|
|
||||||
|
|
||||||
#include "jtag_core/jtag_core.h"
|
|
||||||
|
|
||||||
extern const char cmd_exit_help[];
|
|
||||||
|
|
||||||
int cmd_exit(jtag_core *jc, int argc, char *argv[]);
|
|
||||||
|
|
||||||
#endif /* _CMD_EXIT_H */
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "help.h"
|
|
||||||
|
|
||||||
int cmd_help(jtag_core *jc, int argc, char **argv) {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#ifndef _CMD_HELP_H
|
|
||||||
#define _CMD_HELP_H
|
|
||||||
|
|
||||||
#include "jtag_core/jtag_core.h"
|
|
||||||
|
|
||||||
int cmd_help(jtag_core *jc, int argc, char *argv[]);
|
|
||||||
|
|
||||||
#endif /* _CMD_help_H */
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "list_probes.h"
|
|
||||||
#include "../utils.h"
|
|
||||||
|
|
||||||
const char cmd_list_probes_help[] = "Bla bla.";
|
|
||||||
|
|
||||||
struct probe {
|
|
||||||
int drv;
|
|
||||||
int probe;
|
|
||||||
int probe_id;
|
|
||||||
char name[PROBE_NAME_SIZE];
|
|
||||||
};
|
|
||||||
|
|
||||||
int list_probes(jtag_core *jc, struct probe probes[], int show) {
|
|
||||||
int i = 0;
|
|
||||||
int j = 0;
|
|
||||||
int n = 0;
|
|
||||||
|
|
||||||
char probe_name[PROBE_NAME_SIZE] = {0};
|
|
||||||
int n_probe_drv = 0;
|
|
||||||
int n_probes = 0;
|
|
||||||
|
|
||||||
/* Drivers and probes */
|
|
||||||
n_probe_drv = jtagcore_get_number_of_probes_drv(jc);
|
|
||||||
if (n_probe_drv > 0) {
|
|
||||||
if (0 != show) printf("Found a debug probe driver:\n");
|
|
||||||
} else {
|
|
||||||
if (0 != show) printf("No probes driver found\n");
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i=0;i<n_probe_drv;i++) {
|
|
||||||
if (0 != show) printf(" JTAG probe driver %d\n", i);
|
|
||||||
|
|
||||||
n_probes = jtagcore_get_number_of_probes(jc, i);
|
|
||||||
|
|
||||||
if (n_probes > 0) {
|
|
||||||
|
|
||||||
if (0 != show) printf("Found a debug probe:\n");
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if (0 != show) printf("No probe found.\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (j=0;j<n_probes;j++) {
|
|
||||||
jtagcore_get_probe_name(jc, PROBE_ID(i,j), probe_name);
|
|
||||||
|
|
||||||
if (n < PROBES_MAX_NUM) {
|
|
||||||
probes[n].drv = i;
|
|
||||||
probes[n].probe = j;
|
|
||||||
probes[n].probe_id = PROBE_ID(i,j);
|
|
||||||
strncpy(probes[n].name, probe_name, PROBE_NAME_SIZE);
|
|
||||||
}
|
|
||||||
if (0 != show) {
|
|
||||||
printf(" JTAG probe %d: ", n+1);
|
|
||||||
printf("%s.\n", probe_name);
|
|
||||||
}
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cmd_list_probes(jtag_core *jc, int argc, char *argv[]) {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#ifndef _LIST_PROBES_H
|
|
||||||
#define _LIST_PROBES_H
|
|
||||||
|
|
||||||
#include "jtag_core/jtag_core.h"
|
|
||||||
|
|
||||||
extern const char cmd_list_probes_help[];
|
|
||||||
|
|
||||||
int cmd_list_probes(jtag_core *jc, int argc, char *argv[]);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "scan.h"
|
|
||||||
#include "../utils.h"
|
|
||||||
|
|
||||||
const char cmd_scan_help[] = "Bla bla.";
|
|
||||||
|
|
||||||
int scan(jtag_core *jc, int probe_id, int *ndevs, unsigned long ids[], int show) {
|
|
||||||
int err = JTAG_CORE_NO_ERROR;
|
|
||||||
int n = 0;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
if (0 != show) printf("Devices scan in progress...\n");
|
|
||||||
|
|
||||||
err = jtagcore_scan_and_init_chain(jc);
|
|
||||||
if (err < 0) {
|
|
||||||
if (0 != show) printf("Impossible to scan the JTAG chain");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
n = jtagcore_get_number_of_devices(jc);
|
|
||||||
if (n < 0) {
|
|
||||||
if (0 != show) printf("Error while getting the number of devices on the chain.\n");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
*ndevs = n;
|
|
||||||
for (i=0;i < MIN(n, DEVICES_SCAN_MAX);i++) {
|
|
||||||
ids[i] = jtagcore_get_dev_id(jc, i);
|
|
||||||
if (0 != show) printf(" device %d : 0x%08x\n", i, ids[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 != show) printf("Done.\n");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cmd_scan(jtag_core *jc, int argc, char *argv[]) {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
#ifndef _CMDS_SCAN_H
|
|
||||||
#define _CMDS_SCAN_H
|
|
||||||
|
|
||||||
#include "jtag_core/jtag_core.h"
|
|
||||||
|
|
||||||
extern const char cmd_scan_help[];
|
|
||||||
|
|
||||||
int cmd_scan(jtag_core *jc, int argc, char *argv[]);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "select_probe.h"
|
|
||||||
|
|
||||||
const char cmd_select_probe_help[] = "Bla bla.";
|
|
||||||
|
|
||||||
int cmd_select_probe(jtag_core *jc, int argc, char *argv[]) {
|
|
||||||
int error = 0;
|
|
||||||
|
|
||||||
// error = jtagcore_select_and_open_probe(jc, probe_id);
|
|
||||||
if (error < 0) {
|
|
||||||
printf("Impossible to open the selected probe.\n");
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#ifndef _SELECT_PROBE_H
|
|
||||||
#define _SELECT_PROBE_H
|
|
||||||
|
|
||||||
#include "jtag_core/jtag_core.h"
|
|
||||||
|
|
||||||
extern const char cmd_select_probe_help[];
|
|
||||||
|
|
||||||
int cmd_select_probe(jtag_core *jc, int argc, char *argv[]);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
96
bs/init.c
96
bs/init.c
@@ -1,24 +1,4 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
#include "common.h"
|
|
||||||
#include "cmds/help.h"
|
|
||||||
#include "cmds/scan.h"
|
|
||||||
#include "cmds/list_probes.h"
|
|
||||||
#include "cmds/exit.h"
|
|
||||||
#include "cmds/select_probe.h"
|
|
||||||
|
|
||||||
// Table des commandes internes
|
|
||||||
Command commands[] = {
|
|
||||||
{"help", cmd_help, NULL},
|
|
||||||
{"list_probes", cmd_list_probes, cmd_list_probes_help},
|
|
||||||
{"scan", cmd_scan, cmd_scan_help},
|
|
||||||
{"select_probe", cmd_select_probe, cmd_select_probe_help},
|
|
||||||
{"exit", cmd_exit, cmd_exit_help},
|
|
||||||
{NULL, NULL}};
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -27,42 +7,33 @@ Command commands[] = {
|
|||||||
#include "config/version.h"
|
#include "config/version.h"
|
||||||
#include "script/env.h"
|
#include "script/env.h"
|
||||||
#include "script/script.h"
|
#include "script/script.h"
|
||||||
|
|
||||||
#include "config/config_script.h"
|
#include "config/config_script.h"
|
||||||
|
|
||||||
|
#include "init.h"
|
||||||
|
|
||||||
void jprint(jtag_core *jc, const char *msg)
|
void jprint(jtag_core *jc, const char *msg)
|
||||||
{
|
{
|
||||||
printf(msg);
|
fputs(msg, stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
int script_print(script_ctx *sctx, enum MSGTYPE typ, char *string, ...)
|
int script_print(script_ctx *sctx, enum MSGTYPE typ, char *string, ...)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
char msg[64] = {0};
|
const char *prefix = "";
|
||||||
va_list args;
|
va_list args;
|
||||||
|
|
||||||
switch (typ)
|
switch (typ)
|
||||||
{
|
{
|
||||||
case MSG_DEBUG:
|
case MSG_DEBUG: prefix = "DEBUG : "; break;
|
||||||
strcpy(msg, "DEBUG :");
|
case MSG_INFO_1: prefix = "INFO : "; break;
|
||||||
break;
|
case MSG_WARNING: prefix = "WARNING : "; break;
|
||||||
case MSG_INFO_1:
|
case MSG_ERROR: prefix = "ERROR : "; break;
|
||||||
strcpy(msg, "INFO :");
|
|
||||||
break;
|
|
||||||
case MSG_WARNING:
|
|
||||||
strcpy(msg, "WARNING :");
|
|
||||||
break;
|
|
||||||
case MSG_ERROR:
|
|
||||||
strcpy(msg, "ERROR :");
|
|
||||||
break;
|
|
||||||
case MSG_INFO_0:
|
case MSG_INFO_0:
|
||||||
default:
|
default: prefix = ""; break;
|
||||||
strcpy(msg, "");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
va_start(args, string);
|
va_start(args, string);
|
||||||
ret = printf(msg);
|
ret = fputs(prefix, stdout);
|
||||||
ret += vprintf(string, args);
|
ret += vprintf(string, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -70,64 +41,61 @@ int script_print(script_ctx *sctx, enum MSGTYPE typ, char *string, ...)
|
|||||||
|
|
||||||
void bsexp_init(jtag_core **jc, script_ctx **sctx)
|
void bsexp_init(jtag_core **jc, script_ctx **sctx)
|
||||||
{
|
{
|
||||||
// JTAG core initialization
|
|
||||||
*jc = jtagcore_init();
|
*jc = jtagcore_init();
|
||||||
if (NULL == *jc)
|
if (NULL == *jc)
|
||||||
goto end;
|
return;
|
||||||
|
|
||||||
// Environment initialization
|
|
||||||
(*jc)->envvar = (void *)initEnv(NULL, NULL);
|
(*jc)->envvar = (void *)initEnv(NULL, NULL);
|
||||||
if (NULL == (*jc)->envvar) {
|
if (NULL == (*jc)->envvar) {
|
||||||
jtagcore_deinit(*jc);
|
jtagcore_deinit(*jc);
|
||||||
*jc = NULL;
|
*jc = NULL;
|
||||||
goto end;
|
return;
|
||||||
}
|
}
|
||||||
jtagcore_setEnvVar(*jc, "VERSION", "v" APP_VER_STR(APP_VER));
|
jtagcore_setEnvVar(*jc, "VERSION", "v" APP_VER_STR(APP_VER));
|
||||||
|
|
||||||
// Scripts initialization
|
|
||||||
*sctx = jtagcore_initScript(*jc);
|
*sctx = jtagcore_initScript(*jc);
|
||||||
if (NULL == *sctx) {
|
if (NULL == *sctx) {
|
||||||
deinitEnv((*jc)->envvar);
|
deinitEnv((*jc)->envvar);
|
||||||
jtagcore_deinit(*jc);
|
jtagcore_deinit(*jc);
|
||||||
*jc = NULL;
|
*jc = NULL;
|
||||||
goto end;
|
return;
|
||||||
}
|
}
|
||||||
setOutputFunc_script(*sctx, script_print);
|
setOutputFunc_script(*sctx, script_print);
|
||||||
execute_ram_script(*sctx, config_script, config_script_len);
|
execute_ram_script(*sctx, config_script, config_script_len);
|
||||||
execute_file_script(*sctx, "config.script");
|
/* User override is optional — silence the engine's "not found" message. */
|
||||||
|
{
|
||||||
|
FILE *f = fopen("config.script", "r");
|
||||||
|
if (f) {
|
||||||
|
fclose(f);
|
||||||
|
execute_file_script(*sctx, "config.script");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Log printing callback */
|
|
||||||
if (jtagcore_set_logs_callback(*jc, jprint) < 0)
|
if (jtagcore_set_logs_callback(*jc, jprint) < 0)
|
||||||
{
|
{
|
||||||
printf("Impossible to define the logs callback!\n");
|
fputs("Impossible to define the logs callback!\n", stderr);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (jtagcore_getEnvVar(*jc, "LOG_MESSAGES_FILTER_LEVEL", NULL))
|
||||||
{
|
{
|
||||||
if (jtagcore_getEnvVar(*jc, "LOG_MESSAGES_FILTER_LEVEL", NULL))
|
jtagcore_set_logs_level(*jc, jtagcore_getEnvVarValue(*jc, "LOG_MESSAGES_FILTER_LEVEL"));
|
||||||
{
|
}
|
||||||
jtagcore_set_logs_level(*jc, jtagcore_getEnvVarValue(*jc, "LOG_MESSAGES_FILTER_LEVEL"));
|
if (jtagcore_getEnvVar(*jc, "LOG_MESSAGES_FILE_OUTPUT", NULL))
|
||||||
}
|
{
|
||||||
if (jtagcore_getEnvVar(*jc, "LOG_MESSAGES_FILE_OUTPUT", NULL))
|
jtagcore_set_logs_file(*jc, jtagcore_getEnvVar(*jc, "LOG_MESSAGES_FILE_OUTPUT", NULL));
|
||||||
{
|
|
||||||
jtagcore_set_logs_file(*jc, jtagcore_getEnvVar(*jc, "LOG_MESSAGES_FILE_OUTPUT", NULL));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
end:
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void bsexp_deinit(jtag_core *jc, script_ctx *sctx)
|
void bsexp_deinit(jtag_core *jc, script_ctx *sctx)
|
||||||
{
|
{
|
||||||
envvar_entry *env = NULL;
|
if (NULL != sctx)
|
||||||
|
|
||||||
if (NULL != jc)
|
|
||||||
{
|
{
|
||||||
deinit_script(sctx);
|
deinit_script(sctx);
|
||||||
}
|
}
|
||||||
if (NULL != jc)
|
if (NULL != jc)
|
||||||
{
|
{
|
||||||
env = jc->envvar;
|
deinitEnv((envvar_entry *)jc->envvar);
|
||||||
deinitEnv(env);
|
|
||||||
jtagcore_deinit(jc);
|
jtagcore_deinit(jc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
11
bs/init.h
11
bs/init.h
@@ -3,17 +3,8 @@
|
|||||||
|
|
||||||
#include "config/bs_defines.h"
|
#include "config/bs_defines.h"
|
||||||
|
|
||||||
typedef int (*command_call)(jtag_core *jc, int argc, char *argv[]);
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char *name;
|
|
||||||
command_call cmd_call;
|
|
||||||
} Command;
|
|
||||||
|
|
||||||
extern Command commands[];
|
|
||||||
|
|
||||||
int script_print(script_ctx *sctx, enum MSGTYPE typ, char *string, ...);
|
int script_print(script_ctx *sctx, enum MSGTYPE typ, char *string, ...);
|
||||||
void bsexp_init(jtag_core **jc, script_ctx **sctx);
|
void bsexp_init(jtag_core **jc, script_ctx **sctx);
|
||||||
void bsexp_deinit(jtag_core *jc, script_ctx *sctx);
|
void bsexp_deinit(jtag_core *jc, script_ctx *sctx);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
182
bs/main.c
182
bs/main.c
@@ -1,5 +1,4 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
@@ -7,123 +6,116 @@
|
|||||||
#include <readline/history.h>
|
#include <readline/history.h>
|
||||||
|
|
||||||
#include "config/bs_defines.h"
|
#include "config/bs_defines.h"
|
||||||
#include "utils.h"
|
#include "config/version.h"
|
||||||
#include "init.h"
|
#include "jtag_core/jtag_core.h"
|
||||||
#include "args.h"
|
|
||||||
#include "script/script.h"
|
#include "script/script.h"
|
||||||
|
#include "init.h"
|
||||||
|
|
||||||
// int main(int argc, char *argv[]) {
|
#define PROMPT "bs_explorer> "
|
||||||
// int success = 0;
|
|
||||||
// int n_probes = 0;
|
|
||||||
// int i = 0;
|
|
||||||
// int error = 0;
|
|
||||||
// jtag_core *jc = NULL;
|
|
||||||
|
|
||||||
// struct args a = {0};
|
static jtag_core *jc = NULL;
|
||||||
// struct probe probes[PROBES_MAX_NUM] = {0};
|
static script_ctx *sctx = NULL;
|
||||||
// unsigned long dev_ids[DEVICES_SCAN_MAX] = {0};
|
|
||||||
// int ndevs = 0;
|
|
||||||
|
|
||||||
// success = parse_args(&a, argc, argv);
|
static void handle_sigint(int sig)
|
||||||
// if (EXIT_FAILURE == success) exit(EXIT_FAILURE);
|
{
|
||||||
|
(void)sig;
|
||||||
// jc = bsexp_init();
|
fputs("\n", stdout);
|
||||||
// if (NULL == jc) {
|
|
||||||
// error = JTAG_CORE_MEM_ERROR;
|
|
||||||
// goto err;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /* List the probes (and display if asked) */
|
|
||||||
// n_probes = list_probes(jc, probes, a.list);
|
|
||||||
|
|
||||||
// i = 0;
|
|
||||||
// while ((i<MAX_COMMANDS) && (a.cmds[i] != NO_COMMAND)) {
|
|
||||||
// switch (a.cmds[i]) {
|
|
||||||
// case COMMAND_SCAN:
|
|
||||||
// if ((0 >= a.probe) || (a.probe > MIN(n_probes, PROBES_MAX_NUM))) goto err;
|
|
||||||
// error = scan(jc, probes[a.probe-1].probe_id, &ndevs, dev_ids, 1);
|
|
||||||
// break;
|
|
||||||
// default:
|
|
||||||
// printf("Unknown command.");
|
|
||||||
// goto err;
|
|
||||||
// }
|
|
||||||
// i++;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// goto end;
|
|
||||||
|
|
||||||
// err:
|
|
||||||
// printf("Exited with error (%d).\n", error);
|
|
||||||
|
|
||||||
// end:
|
|
||||||
// jtagcore_deinit(jc);
|
|
||||||
// return error;
|
|
||||||
// }
|
|
||||||
|
|
||||||
jtag_core *jc = NULL;
|
|
||||||
script_ctx *sctx = NULL;
|
|
||||||
|
|
||||||
// Fonction de gestion du signal
|
|
||||||
void handle_sigint(int sig) {
|
|
||||||
bsexp_deinit(jc, sctx);
|
bsexp_deinit(jc, sctx);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int execute_command(script_ctx *sctx, char *line)
|
static char *command_generator(const char *text, int state)
|
||||||
{
|
{
|
||||||
int error = 0;
|
static int idx;
|
||||||
error = execute_line_script(sctx, line);
|
static size_t len;
|
||||||
return error;
|
const char *name;
|
||||||
|
|
||||||
|
if (!state) {
|
||||||
|
idx = 0;
|
||||||
|
len = strlen(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((name = script_commands_list[idx].command) != NULL) {
|
||||||
|
idx++;
|
||||||
|
if (strncmp(name, text, len) == 0) {
|
||||||
|
return strdup(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
static char **bs_completion(const char *text, int start, int end)
|
||||||
|
{
|
||||||
|
(void)end;
|
||||||
|
rl_attempted_completion_over = 0;
|
||||||
|
if (start == 0) {
|
||||||
|
return rl_completion_matches(text, command_generator);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int is_blank(const char *s)
|
||||||
|
{
|
||||||
|
while (*s) {
|
||||||
|
if (*s != ' ' && *s != '\t') return 0;
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_banner(void)
|
||||||
|
{
|
||||||
|
int n_drv = jtagcore_get_number_of_probes_drv(jc);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
printf(" Boundary Scan Explorer " APP_VER_STR(APP_VER) "\n");
|
||||||
|
printf(" Based on Viveris jtag-boundary-scanner\n");
|
||||||
|
printf("\n");
|
||||||
|
printf(" %d probe driver(s) available.\n", n_drv);
|
||||||
|
printf(" Type 'help' or '?' to list commands, 'exit' or Ctrl-D to quit.\n");
|
||||||
|
printf(" <Tab> completes commands.\n");
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
{
|
{
|
||||||
char *line = NULL;
|
char *line = NULL;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
int cmd_argc = 0;
|
|
||||||
|
|
||||||
bsexp_init(&jc, &sctx);
|
bsexp_init(&jc, &sctx);
|
||||||
script_print(sctx, MSG_NONE, "\n");
|
if (NULL == jc || NULL == sctx) {
|
||||||
if ((NULL == jc) || (NULL == sctx))
|
fputs("JTAG Core initialization failed!\n", stderr);
|
||||||
{
|
return JTAG_CORE_MEM_ERROR;
|
||||||
error = JTAG_CORE_MEM_ERROR;
|
|
||||||
printf("JTAG Core initialization failed!\n");
|
|
||||||
goto err_no_deinit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
signal(SIGINT, handle_sigint);
|
signal(SIGINT, handle_sigint);
|
||||||
while (1)
|
rl_attempted_completion_function = bs_completion;
|
||||||
{
|
rl_readline_name = "bs_explorer";
|
||||||
line = readline("bs_explorer> ");
|
|
||||||
if (line == NULL)
|
print_banner();
|
||||||
{
|
|
||||||
|
while ((line = readline(PROMPT)) != NULL) {
|
||||||
|
if (is_blank(line)) {
|
||||||
|
free(line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strcmp(line, "exit") == 0 || strcmp(line, "quit") == 0) {
|
||||||
|
free(line);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (*line)
|
add_history(line);
|
||||||
{
|
|
||||||
add_history(line);
|
error = execute_line_script(sctx, line);
|
||||||
}
|
if (error != JTAG_CORE_NO_ERROR && error != JTAG_CORE_NOT_FOUND) {
|
||||||
if (strcmp(line, "exit") == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (strcmp(line, "quit") == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
error = execute_command(sctx, line);
|
|
||||||
if (0 == error)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("Command failed with code: %d\n", error);
|
printf("Command failed with code: %d\n", error);
|
||||||
}
|
}
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line == NULL) {
|
||||||
|
fputs("\n", stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
err_no_deinit:
|
|
||||||
exit(error);
|
|
||||||
err:
|
|
||||||
printf("Failed with error (%d)", error);
|
|
||||||
end:
|
|
||||||
bsexp_deinit(jc, sctx);
|
bsexp_deinit(jc, sctx);
|
||||||
exit(error);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
14
bs/utils.h
14
bs/utils.h
@@ -1,14 +0,0 @@
|
|||||||
#ifndef _UTILS_H
|
|
||||||
#define _UTILS_H
|
|
||||||
|
|
||||||
|
|
||||||
#define MAX_LINE 1024
|
|
||||||
#define MAX_ARGS 16
|
|
||||||
#define PROBES_MAX_NUM 16
|
|
||||||
#define PROBE_NAME_SIZE 64
|
|
||||||
#define DEVICES_SCAN_MAX 32
|
|
||||||
|
|
||||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
|
||||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
|
||||||
|
|
||||||
#endif
|
|
||||||
Reference in New Issue
Block a user