blob: 8825b208c6e6625197747e24cc8e357aa58bd317 [file] [log] [blame]
// Copyright 2020 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/fdio/directory.h>
#include <lib/zx/channel.h>
#include <stdlib.h>
#include <unistd.h>
#include <string>
#include "gpioutil.h"
namespace {
constexpr size_t kArgDevice = 2;
} // namespace
// LINT.IfChange
static void usage() {
printf(
"Usage: gpioutil <command> [<name>] [<value>]\n\n"
"List, read from, write to, and configure GPIOs.\n\n"
"Commands:\n"
" list | l List the known GPIOs. Each GPIO is represented by 2 values.\n"
" Example: `[gpio-0] GPIO_HW_ID_3`. The value inside the\n"
" brackets (`gpio-0`) can be ignored. The value after the brackets\n"
" (`GPIO_HW_ID_3`) is the <name> value to provide to other gpioutil\n"
" commands. GPIO names are defined in the driver source code and\n"
" usually match the datasheet's name for the GPIO. Example:\n"
" "
"https://cs.opensource.google/fuchsia/fuchsia/+/main:src/devices/board/drivers/vim3/"
"vim3-gpio.cc;l=72\n"
" read | r Read the current value of <name>. Possible return values are\n"
" `0` (LOW) or `1` (HIGH).\n"
" write | w Write to <name>. <value> should be `0` (LOW) or `1` (HIGH).\n"
" in | i Configure <name> as IN. <value> is the resistor pull and its value\n"
" should be `up`, `down`, or `none`.\n"
" out | o Configure <name> as OUT. <value> is the initial OUT\n"
" state and its value should be `0` (LOW) or `1` (HIGH).\n"
" drive | d Set the drive strength of <name>. <value> should be the\n"
" drive strength value in microamps.\n"
" interrupt | q Get the interrupt corresponding to <name> with flags <value>. Wait for\n"
" it to trigger once, then exit. <value> should be `default`, \n"
" `edge-high`, `edge-low`, `edge-both`, `level-low`, or `level-high`.\n"
" help | h Print this help text.\n\n"
"Examples:\n"
" List GPIO pins:\n"
" $ gpioutil list\n"
" [gpio-0] GPIO_HW_ID_3\n"
" [gpio-1] GPIO_SOC_TH_BOOT_MODE_L\n"
" ...\n\n"
" Read the current value of <name>:\n"
" $ gpioutil read GPIO_HW_ID_3\n"
" GPIO Value: 1\n\n"
" Write a LOW value to a GPIO pin:\n"
" $ gpioutil write GPIO_HW_ID_3 0\n\n"
" Configure a GPIO pin as IN with a pull-down resistor:\n"
" $ gpioutil in GPIO_HW_ID_3 down\n\n"
" Configure a GPIO pin as OUT with an initial value of HIGH:\n"
" $ gpioutil out GPIO_HW_ID_3 1\n\n"
" Get the current drive strength in microamps of a GPIO pin:\n"
" $ gpioutil drive GPIO_HW_ID_3\n"
" Drive Strength: 500 ua\n\n"
" Set the drive strength of a GPIO pin to 500 microamps:\n"
" $ gpioutil drive GPIO_HW_ID_3 500\n"
" Set drive strength to 500\n\n"
" Wait for a falling edge on a GPIO:\n"
" $ gpioutil interrupt GPIO_HW_ID_3 edge-low\n"
" Received interrupt at time 12345\n\n");
}
// LINT.ThenChange(//docs/reference/tools/hardware/gpioutil.md)
int main(int argc, char** argv) {
GpioFunc func;
uint8_t write_value, out_value;
uint64_t ds_ua;
fuchsia_hardware_gpio::wire::GpioFlags in_flag;
uint32_t interrupt_flags;
if (ParseArgs(argc, argv, &func, &write_value, &in_flag, &out_value, &ds_ua, &interrupt_flags)) {
fprintf(stderr, "Unable to parse arguments!\n\n");
usage();
return -1;
}
// Handle functions without any parameter.
if (func == List) {
zx::result result = ListGpios();
if (result.is_error()) {
fprintf(stderr, "Failed to list GPIOs: %s\n", result.status_string());
return -1;
}
return 0;
}
int ret = 0;
if (access(argv[kArgDevice], F_OK) == 0) {
// Access by device path
zx::result client_end = component::Connect<fuchsia_hardware_gpio::Gpio>(argv[kArgDevice]);
if (client_end.is_error()) {
fprintf(stderr, "Could not connect to client from %s: %s\n", argv[kArgDevice],
client_end.status_string());
usage();
return -1;
}
fidl::WireSyncClient<fuchsia_hardware_gpio::Gpio> client(std::move(client_end.value()));
ret = ClientCall(std::move(client), func, write_value, in_flag, out_value, ds_ua,
interrupt_flags);
} else {
// Access by GPIO name
auto client = FindGpioClientByName(argv[kArgDevice]);
if (client.is_error()) {
fprintf(stderr, "Unable to connect GPIO by name '%s', st = %d\n\n", argv[kArgDevice],
client.status_value());
usage();
return -1;
}
ret = ClientCall(std::move(*client), func, write_value, in_flag, out_value, ds_ua,
interrupt_flags);
}
if (ret == -1) {
fprintf(stderr, "Client call failed!\n\n");
usage();
}
return ret;
}