Skip to content

Commit

Permalink
vserial tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
nickchan2 committed Mar 31, 2024
1 parent bacb4a8 commit bcea1d0
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 74 deletions.
53 changes: 29 additions & 24 deletions vserial/examples/vserial_print.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,31 @@
*/

#include "../vserial.h"
#include <string>
#include <iostream>
#include <variant>

#include <fcntl.h>
#include <iostream>
#include <string>
#include <unistd.h>

#include <variant>

/**
* @brief A program that shows how the creat_psudeo_serial() function can be used.
* To compile, run g++ -std=c++20 vserial.cc ./examples/vserial_print.cc
*
*/
int main(){
std::variant<agi::vserial::Res, agi::vserial::Error_Res> pseudo_terminal_return = agi::vserial::create_pseudo_serial();
if(std::holds_alternative<agi::vserial::Res>(pseudo_terminal_return)){
agi::vserial::Res pseudo_terminal = std::get<agi::vserial::Res>(pseudo_terminal_return);
std::cout<<"The serial port can be found at "<<pseudo_terminal.file_path<<std::endl;
int main()
{
auto const pt_return = agi::vserial::create_pseudo_serial();
if (std::holds_alternative<agi::vserial::PtInfo>(pt_return)) {
auto const pt_info = std::get<agi::vserial::PtInfo>(pt_return);
std::cout << "The serial port can be found at " << pt_info.file_path << std::endl;
char buffer[256];
while (true) {
ssize_t bytesRead = read(pseudo_terminal.fd, buffer, sizeof(buffer));
if (bytesRead > 0) {
ssize_t const bytes_read = read(pt_info.fd, buffer, sizeof(buffer));
if (bytes_read > 0) {
// Data received, do something with it
std::cout<<buffer<<std::flush;
} else if (bytesRead == 0) {
std::cout << buffer << std::flush;
} else if (bytes_read == 0) {
// No more data to read, exit loop
break;
} else {
Expand All @@ -36,17 +37,21 @@ int main(){
break;
}
}
close(pseudo_terminal.fd);
}else{
agi::vserial::Error_Res pseudo_terminal_error = std::get<agi::vserial::Error_Res>(pseudo_terminal_return);
if(pseudo_terminal_error.open_pt != 0){
std::cout<<"Error opening /dev/ptmx"<<std::endl;
}else if(pseudo_terminal_error.grantpt != 0){
std::cout<<"Error calling grantpt"<<std::endl;
}else if(pseudo_terminal_error.unlockpt != 0){
std::cout<<"Error calling unlockpt"<<std::endl;
}else if(pseudo_terminal_error.ptsname){
std::cout<<"Error calling ptsname"<<std::endl;
close(pt_info.fd);
} else {
auto const pt_error = std::get<agi::vserial::Error>(pt_return);
switch (pt_error.sys_call) {
case agi::vserial::Error::SysCall::OPEN:
std::cout << "Error opening /dev/ptmx" << std::endl;
break;
case agi::vserial::Error::SysCall::GRANTPT:
std::cout << "Error calling grantpt" << std::endl;
break;
case agi::vserial::Error::SysCall::UNLOCKPT:
std::cout << "Error calling unlockpt" << std::endl;
break;
case agi::vserial::Error::SysCall::PTSNAME:
std::cout << "Error calling ptsname" << std::endl;
}
}
return 0;
Expand Down
62 changes: 33 additions & 29 deletions vserial/vserial.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,48 +5,52 @@

#include "vserial.h"



std::variant<agi::vserial::Res, agi::vserial::Error_Res> agi::vserial::create_pseudo_serial(){
agi::vserial::Res return_value;

int pt_fd = open("/dev/ptmx", O_RDWR | O_NOCTTY);
if (pt_fd < 0) {
agi::vserial::Error_Res error_return_value;
error_return_value.open_pt = pt_fd;
return error_return_value;
#include <array>
#include <fcntl.h>
#include <unistd.h>
#include <variant>

std::variant<agi::vserial::PtInfo, agi::vserial::Error> agi::vserial::create_pseudo_serial() {
const int pt_fd = open("/dev/ptmx", O_RDWR | O_NOCTTY); // NOLINT(*-signed-bitwise)
if (pt_fd < 0) {
return agi::vserial::Error{
.sys_call = agi::vserial::Error::SysCall::OPEN,
.errno_val = errno
};
}

// Grant access to the slave pseudo-terminal
if (grantpt(pt_fd) == -1) {
if (grantpt(pt_fd) < 0) {
close(pt_fd);
agi::vserial::Error_Res error_return_value;
error_return_value.grantpt = -1;
return return_value;
return agi::vserial::Error{
.sys_call = agi::vserial::Error::SysCall::GRANTPT,
.errno_val = errno
};
}

// Unlock the pseudo-terminal
if (unlockpt(pt_fd) == -1) {
if (unlockpt(pt_fd) < 0) {
close(pt_fd);
agi::vserial::Error_Res error_return_value;
error_return_value.unlockpt = -1;
return return_value;
return agi::vserial::Error{
.sys_call = agi::vserial::Error::SysCall::UNLOCKPT,
.errno_val = errno
};
}

// Get the name of the slave pseudo-terminal
const char* pts_name = ptsname(pt_fd);
constexpr int MAX_PTSNAME_LEN = 100;
std::array<char, MAX_PTSNAME_LEN> pts_name{};

// Check if ptsname returned a valid string
if (pts_name == nullptr) {
// Return empty values if ptsname failed
if (ptsname_r(pt_fd, pts_name.data(), pts_name.size()) < 0) {
close(pt_fd);
agi::vserial::Error_Res error_return_value;
error_return_value.ptsname = true;
return error_return_value;
return agi::vserial::Error{
.sys_call = agi::vserial::Error::SysCall::PTSNAME,
.errno_val = errno
};
}

// Convert the C-style string to a C++ std::string
return_value.file_path = std::string(pts_name);
return_value.fd = pt_fd;
return return_value;
return agi::vserial::PtInfo{
.file_path = pts_name.data(),
.fd = pt_fd
};
}
43 changes: 22 additions & 21 deletions vserial/vserial.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,34 @@
*/

#pragma once
#include <fcntl.h>
#include <iostream>
#include <unistd.h>

#include <string>
#include <variant>

namespace agi::vserial {

/**
* @brief A function to open a pseudo terminal.
*
* @return Struct containing the fd and the filePath
*/

struct Res {
std::string file_path;
int fd;
};


struct Error_Res {
int open_pt = 0;
int grantpt = 0;
int unlockpt = 0;
bool ptsname = false;
/**
* @brief A function to open a pseudo terminal.
*
* @return Struct containing the fd and the file path
*/

struct PtInfo {
std::string file_path;
int fd;
};

struct Error {
enum class SysCall {
OPEN,
GRANTPT,
UNLOCKPT,
PTSNAME
};
SysCall sys_call;
int errno_val;
};

std::variant<agi::vserial::PtInfo, agi::vserial::Error> create_pseudo_serial();

std::variant<agi::vserial::Res, agi::vserial::Error_Res> create_pseudo_serial();
} // namespace agi::vserial

0 comments on commit bcea1d0

Please sign in to comment.