blob: 3584083910dc9356b59be48fb6b59a951c9b2105 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <ctype.h>
#include <errno.h>
#include <lib/component/incoming/cpp/protocol.h>
#include <lib/spi/spi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <zircon/status.h>
#include <string>
void usage(char* prog) {
fprintf(stderr, "usage:\n");
fprintf(stderr, " %s DEVICE r LENGTH\n", prog);
fprintf(stderr, " %s DEVICE w BYTES ...\n", prog);
fprintf(stderr, " %s DEVICE x BYTES ...\n", prog);
}
void convert_args(char** argv, size_t length, uint8_t* buffer) {
for (size_t i = 0; i < length; i++) {
buffer[i] = static_cast<uint8_t>(strtoul(argv[i], nullptr, 0));
}
}
void print_buffer(uint8_t* buffer, size_t length) {
char ascii[16];
char* a = ascii;
for (size_t i = 0; i < length; i++) {
if (i % 16 == 0) {
printf("%04zx: ", i);
a = ascii;
}
printf("%02x ", buffer[i]);
if (isprint(buffer[i])) {
*a++ = static_cast<char>(buffer[i]);
} else {
*a++ = '.';
}
if (i % 16 == 15) {
printf("|%.16s|\n", ascii);
} else if (i % 8 == 7) {
printf(" ");
}
}
int rem = static_cast<int>(length) % 16;
if (rem != 0) {
int spaces = (16 - rem) * 3;
if (rem < 8) {
spaces++;
}
printf("%*s|%.*s|\n", spaces, "", rem, ascii);
}
}
int main(int argc, char** argv) {
if (argc < 4) {
usage(argv[0]);
return -1;
}
zx::result controller = component::Connect<fuchsia_hardware_spi::Controller>(argv[1]);
if (controller.is_error()) {
fprintf(stderr, "component::Connect(%s): %s\n", argv[1], controller.status_string());
return -1;
}
auto [device, server] = fidl::Endpoints<fuchsia_hardware_spi::Device>::Create();
const fidl::Status result = fidl::WireCall(controller.value())->OpenSession(std::move(server));
if (!result.ok()) {
fprintf(stderr, "(%s)->OpenSession(): %s\n", argv[1], result.status_string());
return -1;
}
switch (argv[2][0]) {
case 'r': {
uint32_t length = static_cast<uint32_t>(std::stoul(argv[3], nullptr, 0));
uint8_t buffer[length];
if (zx_status_t status = spilib_receive(device, buffer, length); status != ZX_OK) {
fprintf(stderr, "error: spilib_receive failed: %s\n", zx_status_get_string(status));
return -1;
}
print_buffer(buffer, length);
break;
}
case 'w': {
size_t length = argc - 3;
uint8_t buffer[length];
convert_args(&argv[3], length, buffer);
if (zx_status_t status = spilib_transmit(device, buffer, length); status != ZX_OK) {
fprintf(stderr, "error: spilib_transmit failed: %s\n", zx_status_get_string(status));
return -1;
}
break;
}
case 'x': {
size_t length = argc - 3;
uint8_t send[length];
uint8_t recv[length];
convert_args(&argv[3], length, send);
if (zx_status_t status = spilib_exchange(device, send, recv, length); status != ZX_OK) {
fprintf(stderr, "error: spilib_exchange failed: %s\n", zx_status_get_string(status));
return -1;
}
print_buffer(recv, length);
break;
}
default:
fprintf(stderr, "%c: unrecognized command\n", argv[2][0]);
usage(argv[0]);
return -1;
}
return 0;
}