diff options
-rw-r--r-- | client/Android.mk | 2 | ||||
-rw-r--r-- | client/peripheral_manager_client_impl.cc | 14 | ||||
-rw-r--r-- | client/peripheral_manager_client_impl.h | 5 | ||||
-rw-r--r-- | client/uart_device_impl.cc | 58 | ||||
-rw-r--r-- | client/uart_device_impl.h | 43 | ||||
-rw-r--r-- | client/uart_unittest.cc | 151 | ||||
-rw-r--r-- | client/wrapper.cc | 48 | ||||
-rw-r--r-- | example/Android.mk | 16 | ||||
-rw-r--r-- | example/pio_uart.cc | 89 | ||||
-rw-r--r-- | include/peripheralmanager/peripheral_manager_client.h | 25 | ||||
-rw-r--r-- | include/peripheralmanager/uart_device.h | 70 |
11 files changed, 519 insertions, 2 deletions
diff --git a/client/Android.mk b/client/Android.mk index 5371a98..d080d3c 100644 --- a/client/Android.mk +++ b/client/Android.mk @@ -46,6 +46,7 @@ LOCAL_SRC_FILES := \ led_impl.cc \ peripheral_manager_client_impl.cc \ spi_device_impl.cc \ + uart_device_impl.cc \ wrapper.cc \ include $(BUILD_SHARED_LIBRARY) @@ -77,5 +78,6 @@ LOCAL_SRC_FILES := \ led_unittest.cc \ peripheral_manager_client_unittest.cc \ spi_unittest.cc \ + uart_unittest.cc \ include $(BUILD_NATIVE_TEST) diff --git a/client/peripheral_manager_client_impl.cc b/client/peripheral_manager_client_impl.cc index 407a40f..4fdb731 100644 --- a/client/peripheral_manager_client_impl.cc +++ b/client/peripheral_manager_client_impl.cc @@ -86,3 +86,17 @@ int PeripheralManagerClientImpl::OpenI2cDevice( int PeripheralManagerClientImpl::ListI2cBuses(std::vector<std::string>* buses) { return client_->ListI2cBuses(buses).serviceSpecificErrorCode(); } + +int PeripheralManagerClientImpl::OpenUartDevice( + const std::string& name, std::unique_ptr<UartDeviceImpl>* device) { + Status status = client_->OpenUartDevice(name); + if (status.isOk()) { + device->reset(new UartDeviceImpl(name, client_)); + } + return status.serviceSpecificErrorCode(); +} + +int PeripheralManagerClientImpl::ListUartDevices( + std::vector<std::string>* list) { + return client_->ListUartDevices(list).serviceSpecificErrorCode(); +} diff --git a/client/peripheral_manager_client_impl.h b/client/peripheral_manager_client_impl.h index 0eb144a..aba4739 100644 --- a/client/peripheral_manager_client_impl.h +++ b/client/peripheral_manager_client_impl.h @@ -24,6 +24,7 @@ #include "i2c_device_impl.h" #include "led_impl.h" #include "spi_device_impl.h" +#include "uart_device_impl.h" class PeripheralManagerClientImpl { public: @@ -46,6 +47,10 @@ class PeripheralManagerClientImpl { std::unique_ptr<I2cDeviceImpl>* device); int ListI2cBuses(std::vector<std::string>* buses); + int OpenUartDevice(const std::string& name, + std::unique_ptr<UartDeviceImpl>* device); + int ListUartDevices(std::vector<std::string>* buses); + private: android::sp<android::os::IPeripheralManagerClient> client_; android::sp<android::IBinder> lifeline_; diff --git a/client/uart_device_impl.cc b/client/uart_device_impl.cc new file mode 100644 index 0000000..1541715 --- /dev/null +++ b/client/uart_device_impl.cc @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "uart_device_impl.h" + +#include <android-base/unique_fd.h> +#include <binder/Status.h> + +using android::binder::Status; + +UartDeviceImpl::UartDeviceImpl( + const std::string& name, + android::sp<android::os::IPeripheralManagerClient> client) + : name_(name), client_(client) {} + +UartDeviceImpl::~UartDeviceImpl() { + client_->ReleaseUartDevice(name_); +} + +int UartDeviceImpl::SetBaudrate(uint32_t baudrate) { + return client_->SetUartDeviceBaudrate(name_, baudrate) + .serviceSpecificErrorCode(); +} + +int UartDeviceImpl::Write(const void* data, + uint32_t size, + uint32_t* bytes_written) { + const uint8_t* d = reinterpret_cast<const uint8_t*>(data); + return client_ + ->UartDeviceWrite(name_, + std::vector<uint8_t>(d, d + size), + reinterpret_cast<int32_t*>(bytes_written)) + .serviceSpecificErrorCode(); +} + +int UartDeviceImpl::Read(void* data, uint32_t size, uint32_t* bytes_read) { + std::vector<uint8_t> v; + Status status = client_->UartDeviceRead( + name_, &v, size, reinterpret_cast<int32_t*>(bytes_read)); + if (status.isOk()) { + memcpy(data, v.data(), *bytes_read); + } + + return status.serviceSpecificErrorCode(); +} diff --git a/client/uart_device_impl.h b/client/uart_device_impl.h new file mode 100644 index 0000000..72d5d4a --- /dev/null +++ b/client/uart_device_impl.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SYSTEM_PERIPHERALMANAGER_UART_DEVICE_IMPL_H_ +#define SYSTEM_PERIPHERALMANAGER_UART_DEVICE_IMPL_H_ + +#include <string> + +#include <android/os/IPeripheralManagerClient.h> +#include <utils/StrongPointer.h> + +class UartDeviceImpl { + public: + UartDeviceImpl(const std::string& name, + android::sp<android::os::IPeripheralManagerClient> client); + + ~UartDeviceImpl(); + + int SetBaudrate(uint32_t baudrate); + + int Write(const void* data, uint32_t size, uint32_t* bytes_written); + + int Read(void* data, uint32_t size, uint32_t* bytes_read); + + private: + std::string name_; + android::sp<android::os::IPeripheralManagerClient> client_; +}; + +#endif // SYSTEM_PERIPHERALMANAGER_UART_DEVICE_IMPL_H_ diff --git a/client/uart_unittest.cc b/client/uart_unittest.cc new file mode 100644 index 0000000..ff46433 --- /dev/null +++ b/client/uart_unittest.cc @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <memory> + +#include <binderwrapper/binder_test_base.h> +#include <binderwrapper/stub_binder_wrapper.h> +#include <gtest/gtest.h> + +#include "fake_devices.h" +#include "peripheral_manager.h" +#include "peripheralmanager/peripheral_manager_client.h" +#include "peripheralmanager/uart_device.h" +#include "uart_driver_sysfs.h" + +using android::CharDeviceFactory; +using android::FakeDeviceFactory; +using android::UartDriverInfo; +using android::UartDriverInfoBase; +using android::UartDriverSysfs; +using android::UartManager; +using android::PeripheralManager; + +// Base class used to test the Uart C API. +// As we rely on static, global managers, we cannot run this tests in parallel. +// Please use -j1 when running theses tests or you may see false negatives. +class UartTest : public android::BinderTestBase { + public: + void SetUp() { + android::sp<PeripheralManager> pman(new PeripheralManager); + android::String8 interface_desc(pman->getInterfaceDescriptor()); + binder_wrapper()->SetBinderForService(interface_desc.string(), pman); + + UartManager* man = UartManager::GetManager(); + + man->RegisterDriver(std::unique_ptr<UartDriverInfoBase>( + new UartDriverInfo<UartDriverSysfs, CharDeviceFactory*>( + &device_factory_))); + + man->RegisterUartDevice("UART0", "/dev/ttyuart0"); + } + + void TearDown() { UartManager::ResetManager(); } + + private: + FakeDeviceFactory device_factory_; +}; + +// Test that we can list the available devices. +TEST_F(UartTest, ListDevices) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + int n = 0; + char** list = BPeripheralManagerClient_listUartDevices(client, &n); + + ASSERT_EQ(1, n); + ASSERT_EQ("UART0", std::string(list[0])); + + free(list[0]); + free(list); + + BPeripheralManagerClient_delete(client); +} + +// Test that we can open a uart device and set the baudrate. +TEST_F(UartTest, OpenDevice) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + BUartDevice* device; + ASSERT_EQ(0, + BPeripheralManagerClient_openUartDevice(client, "UART0", &device)); + + // Can set a valid baudrate. + ASSERT_EQ(0, BUartDevice_setBaudrate(device, 115200)); + + // Setting an invalid baudrate should return an error. + ASSERT_EQ(EINVAL, BUartDevice_setBaudrate(device, 12345)); + + BUartDevice_delete(device); + BPeripheralManagerClient_delete(client); +} + +// Test that we can detect when a device is accessed twice and report an +// appropriate error. +TEST_F(UartTest, HandlesConflict) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + BUartDevice* device_a; + BUartDevice* device_b; + + // Can open UART0 once. + ASSERT_EQ( + 0, BPeripheralManagerClient_openUartDevice(client, "UART0", &device_a)); + + // Can't open it twice. + ASSERT_EQ( + EBUSY, + BPeripheralManagerClient_openUartDevice(client, "UART0", &device_b)); + + // Can open it again once closed. + BUartDevice_delete(device_a); + ASSERT_EQ( + 0, BPeripheralManagerClient_openUartDevice(client, "UART0", &device_b)); + + BUartDevice_delete(device_b); + BPeripheralManagerClient_delete(client); +} + +// Test that we report the right error when trying to open an unknown device. +TEST_F(UartTest, UnknownDevice) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + BUartDevice* device; + ASSERT_EQ( + ENODEV, + BPeripheralManagerClient_openUartDevice(client, "unknown", &device)); + + BPeripheralManagerClient_delete(client); +} + +// Test that we can read and write to a device. +TEST_F(UartTest, ReadWrite) { + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + BUartDevice* device; + ASSERT_EQ(0, + BPeripheralManagerClient_openUartDevice(client, "UART0", &device)); + + char buf[40]; + uint32_t nwritten; + EXPECT_EQ(0, BUartDevice_write(device, buf, 40, &nwritten)); + + uint32_t nread; + EXPECT_EQ(0, BUartDevice_read(device, buf, 40, &nread)); + + BUartDevice_delete(device); + BPeripheralManagerClient_delete(client); +} diff --git a/client/wrapper.cc b/client/wrapper.cc index f23b3b4..f9cc3dc 100644 --- a/client/wrapper.cc +++ b/client/wrapper.cc @@ -22,6 +22,7 @@ #include "peripheral_manager_client_impl.h" #include "peripheralmanager/peripheral_manager_client.h" #include "spi_device_impl.h" +#include "uart_device_impl.h" namespace { @@ -58,6 +59,10 @@ struct BI2cDevice { I2cDeviceImpl* impl; }; +struct BUartDevice { + UartDeviceImpl* impl; +}; + BPeripheralManagerClient* BPeripheralManagerClient_new() { std::unique_ptr<PeripheralManagerClientImpl> impl( new PeripheralManagerClientImpl); @@ -333,3 +338,46 @@ void BI2cDevice_delete(BI2cDevice* device) { delete device->impl; delete device; } + +char** BPeripheralManagerClient_listUartDevices( + const BPeripheralManagerClient* client, int* num_uart_devices) { + std::vector<std::string> list; + client->impl->ListUartDevices(&list); + *num_uart_devices = list.size(); + return ConvertStringVectorToC(list); +} + +int BPeripheralManagerClient_openUartDevice( + const BPeripheralManagerClient* client, + const char* name, + BUartDevice** device) { + std::unique_ptr<UartDeviceImpl> impl; + int ret = client->impl->OpenUartDevice(name, &impl); + if (ret == 0) { + *device = new BUartDevice{impl.release()}; + } + return ret; +} + +int BUartDevice_setBaudrate(const BUartDevice* device, uint32_t baudrate) { + return device->impl->SetBaudrate(baudrate); +} + +int BUartDevice_write(const BUartDevice* device, + const void* data, + uint32_t size, + uint32_t* bytes_written) { + return device->impl->Write(data, size, bytes_written); +} + +int BUartDevice_read(const BUartDevice* device, + void* data, + uint32_t size, + uint32_t* bytes_read) { + return device->impl->Read(data, size, bytes_read); +} + +void BUartDevice_delete(BUartDevice* device) { + delete device->impl; + delete device; +} diff --git a/example/Android.mk b/example/Android.mk index 6afabaf..a4099fb 100644 --- a/example/Android.mk +++ b/example/Android.mk @@ -129,3 +129,19 @@ LOCAL_STATIC_LIBRARIES := peripheral_manager_hal_headers LOCAL_SRC_FILES := headers_are_c89.c include $(BUILD_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := pio_uart +LOCAL_CPP_EXTENSION := .cc +LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter +LOCAL_CFLAGS += -Wno-sign-promo # for libchrome +LOCAL_SHARED_LIBRARIES := \ + libbrillo \ + libchrome \ + libperipheralman \ + libutils \ + +LOCAL_SRC_FILES := \ + pio_uart.cc \ + +include $(BUILD_EXECUTABLE) diff --git a/example/pio_uart.cc b/example/pio_uart.cc new file mode 100644 index 0000000..628a746 --- /dev/null +++ b/example/pio_uart.cc @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <base/logging.h> +#include <brillo/flag_helper.h> + +#include <peripheralmanager/peripheral_manager_client.h> + +int main(int argc, char* argv[]) { + brillo::FlagHelper::Init(argc, argv, "PeripheralManager client."); + logging::InitLogging(logging::LoggingSettings()); + + // Get a client to the PeripheralManager. + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + if (!client) { + LOG(ERROR) << "Failed to connect to client"; + return 1; + } + + BUartDevice* uart; + int ret = BPeripheralManagerClient_openUartDevice(client, "UART1", &uart); + if (ret) { + LOG(ERROR) << "Failed to open UART device"; + return 1; + } + + ret = BUartDevice_setBaudrate(uart, 9600); + + char greeting[] = "What is your name ?\n"; + uint32_t written = 0; + ret = BUartDevice_write(uart, greeting, strlen(greeting), &written); + if (ret) { + LOG(ERROR) << "failed to write: " << strerror(ret); + return 1; + } + + std::string name = ""; + + while (name.size() < 40) { + // If the user entered a newline, everything before is the name. + auto first_newline = name.find(13); + if (first_newline != std::string::npos) { + name.resize(first_newline); + break; + } + + char buffer[40]; + uint32_t bytes_read = 0; + + // Read some data. + ret = BUartDevice_read(uart, buffer, 40, &bytes_read); + if (ret != 0 && ret != EAGAIN) { + LOG(ERROR) << "failed to read: " << strerror(ret); + return 1; + } + LOG(INFO) << "read " << bytes_read << "bytes"; + name.append(buffer, bytes_read); + + // Wait a little before reading again. + // This should be replaced by a more efficient polling mechanism when it is + // ready. + sleep(2); + } + + LOG(INFO) << "hello " << name; + + // Release the UART object. + BUartDevice_delete(uart); + + // Close the connection to PeripheralManager. + BPeripheralManagerClient_delete(client); + + LOG(INFO) << "Exiting"; + return 0; +} diff --git a/include/peripheralmanager/peripheral_manager_client.h b/include/peripheralmanager/peripheral_manager_client.h index 5fdc5ff..51821b0 100644 --- a/include/peripheralmanager/peripheral_manager_client.h +++ b/include/peripheralmanager/peripheral_manager_client.h @@ -23,6 +23,7 @@ #include "peripheralmanager/i2c_device.h" #include "peripheralmanager/led.h" #include "peripheralmanager/spi_device.h" +#include "peripheralmanager/uart_device.h" __BEGIN_DECLS @@ -97,8 +98,9 @@ char** BPeripheralManagerClient_listI2cBuses( int* num_i2c_buses); /// Opens an I2C device and takes ownership of it. -/// @oaram client Pointer to the BPeripheralManagerClient struct. -/// @param name Name of the SPI device. +/// @param client Pointer to the BPeripheralManagerClient struct. +/// @param name Name of the I2C bus. +/// @param address Address of the I2C device. /// @param dev Output pointer to the BI2cDevice struct. Empty on error. /// @return 0 on success, errno on error int BPeripheralManagerClient_openI2cDevice( @@ -107,6 +109,25 @@ int BPeripheralManagerClient_openI2cDevice( uint32_t address, BI2cDevice** dev); +/// Returns the list of UART buses. +/// This does not take ownership into account. +/// The list must be freed by the caller. +/// @param client Pointer to the BPeripheralManagerClient struct. +/// @param num_uart_buses Output pointer to the number of element in the list. +/// @return The list of uart buses. +char** BPeripheralManagerClient_listUartDevices( + const BPeripheralManagerClient* client, int* num_uart_buses); + +/// Opens an UART device and takes ownership of it. +/// @param client Pointer to the BPeripheralManagerClient struct. +/// @param name Name of the UART device. +/// @param dev Output pointer to the BUartDevice struct. Empty on error. +/// @return 0 on success, errno on error +int BPeripheralManagerClient_openUartDevice( + const BPeripheralManagerClient* client, + const char* name, + BUartDevice** dev); + /// Creates a new client. /// @return A pointer to the created client. nullptr on errors. BPeripheralManagerClient* BPeripheralManagerClient_new(); diff --git a/include/peripheralmanager/uart_device.h b/include/peripheralmanager/uart_device.h new file mode 100644 index 0000000..057a068 --- /dev/null +++ b/include/peripheralmanager/uart_device.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SYSTEM_PERIPHERALMANAGER_UART_DEVICE_H_ +#define SYSTEM_PERIPHERALMANAGER_UART_DEVICE_H_ + +#include <sys/cdefs.h> +#include <sys/types.h> + +__BEGIN_DECLS + +/// @defgroup Uart Uart device interface +/// @brief Functions to control an UART device. +/// +/// These functions can be used to control an UART device. +/// @{ + +typedef struct BUartDevice BUartDevice; + +/// Writes to a UART device. +/// @param device Pointer to the BUartDevice struct. +/// @param data Data to write. +/// @param len Size of the data to write. +/// @param bytes_written Output pointer to the number of bytes written. +/// @return 0 on success, errno on error. +int BUartDevice_write(const BUartDevice* device, + const void* data, + uint32_t len, + uint32_t* bytes_written); + +/// Reads from a UART device. +/// @param device Pointer to the BUartDevice struct. +/// @param data Buffer to read the data into. +/// @param len Number of bytes to read. +/// @param bytes_read Output pointer to the number of bytes read. +/// @return 0 on success, errno on error. +int BUartDevice_read(const BUartDevice* device, + void* data, + uint32_t len, + uint32_t* bytes_read); + +/// Sets the input and output speed of a UART device. +/// @param device Pointer to the BUartDevice struct. +/// @param device Uart device to configure. +/// @param baudrate Speed in baud. +/// @return 0 on success, errno on error. +int BUartDevice_setBaudrate(const BUartDevice* device, uint32_t baudrate); + +/// Destroys a BUartDevice struct. +/// @param device Pointer to the BUartDevice struct. +void BUartDevice_delete(BUartDevice* device); + +/// @} + +__END_DECLS + +#endif // SYSTEM_PERIPHERALMANAGER_UART_DEVICE_H_ |