2021-07-19 00:15:13 +02:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// SCSI Target Emulator RaSCSI (*^..^*)
|
|
|
|
// for Raspberry Pi
|
|
|
|
//
|
|
|
|
// Powered by XM6 TypeG Technology.
|
|
|
|
// Copyright (C) 2016-2020 GIMONS
|
|
|
|
// Copyright (C) 2020 akuker
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#include <unistd.h>
|
2021-07-24 02:13:05 +02:00
|
|
|
#include <sstream>
|
|
|
|
#include "rascsi_interface.pb.h"
|
2021-07-19 00:15:13 +02:00
|
|
|
#include "exceptions.h"
|
|
|
|
#include "rasutil.h"
|
|
|
|
|
|
|
|
using namespace std;
|
2021-07-24 02:13:05 +02:00
|
|
|
using namespace rascsi_interface;
|
2021-07-19 00:15:13 +02:00
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
2021-08-04 03:41:18 +02:00
|
|
|
// Serialize/Deserialize protobuf message: Length followed by the actual data.
|
|
|
|
// Little endian is assumed.
|
2021-07-19 00:15:13 +02:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2021-07-24 02:13:05 +02:00
|
|
|
void SerializeMessage(int fd, const google::protobuf::MessageLite& message)
|
2021-07-19 00:15:13 +02:00
|
|
|
{
|
2021-07-24 02:13:05 +02:00
|
|
|
string data;
|
|
|
|
message.SerializeToString(&data);
|
|
|
|
|
2021-07-19 00:15:13 +02:00
|
|
|
// Write the size of the protobuf data as a header
|
2021-07-20 01:41:00 +02:00
|
|
|
int32_t size = data.length();
|
|
|
|
if (write(fd, &size, sizeof(size)) != sizeof(size)) {
|
2021-07-24 02:13:05 +02:00
|
|
|
throw ioexception("Can't write protobuf header");
|
2021-07-20 01:41:00 +02:00
|
|
|
}
|
2021-07-19 00:15:13 +02:00
|
|
|
|
|
|
|
// Write the actual protobuf data
|
2021-08-04 03:41:18 +02:00
|
|
|
uint8_t buf[size];
|
2021-07-19 00:15:13 +02:00
|
|
|
memcpy(buf, data.data(), size);
|
2021-07-20 01:41:00 +02:00
|
|
|
if (write(fd, buf, size) != size) {
|
2021-07-24 02:13:05 +02:00
|
|
|
throw ioexception("Can't write protobuf data");
|
2021-07-20 01:41:00 +02:00
|
|
|
}
|
2021-07-19 00:15:13 +02:00
|
|
|
}
|
|
|
|
|
2021-07-24 02:13:05 +02:00
|
|
|
void DeserializeMessage(int fd, google::protobuf::MessageLite& message)
|
2021-07-19 00:15:13 +02:00
|
|
|
{
|
2021-08-04 03:41:18 +02:00
|
|
|
// Read the header with the size of the protobuf data
|
|
|
|
uint8_t header_buf[4];
|
|
|
|
int bytes_read = ReadNBytes(fd, header_buf, 4);
|
|
|
|
if (bytes_read < 4) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
int32_t size = (header_buf[3] << 24) + (header_buf[2] << 16) + (header_buf[1] << 8) + header_buf[0];
|
2021-07-24 02:13:05 +02:00
|
|
|
|
2021-08-04 03:41:18 +02:00
|
|
|
// Read the binary protobuf data
|
|
|
|
uint8_t data_buf[size];
|
|
|
|
bytes_read = ReadNBytes(fd, data_buf, size);
|
|
|
|
if (bytes_read < size) {
|
|
|
|
throw ioexception("Missing protobuf data");
|
|
|
|
}
|
2021-07-19 00:15:13 +02:00
|
|
|
|
2021-08-04 03:41:18 +02:00
|
|
|
// Create protobuf message
|
|
|
|
string data((const char *)data_buf, size);
|
|
|
|
message.ParseFromString(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
int ReadNBytes(int fd, uint8_t *buf, int n)
|
|
|
|
{
|
|
|
|
int offset = 0;
|
|
|
|
while (offset < n) {
|
|
|
|
ssize_t len = read(fd, buf + offset, n - offset);
|
|
|
|
if (!len) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
offset += len;
|
2021-07-24 02:13:05 +02:00
|
|
|
}
|
2021-08-04 03:41:18 +02:00
|
|
|
|
|
|
|
return offset;
|
2021-07-24 02:13:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// List devices
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
2021-08-08 17:08:58 +02:00
|
|
|
string ListDevices(const PbDevices& devices)
|
|
|
|
{
|
2021-07-24 02:13:05 +02:00
|
|
|
ostringstream s;
|
|
|
|
|
|
|
|
if (devices.devices_size()) {
|
|
|
|
s << endl
|
|
|
|
<< "+----+----+------+-------------------------------------" << endl
|
|
|
|
<< "| ID | UN | TYPE | DEVICE STATUS" << endl
|
|
|
|
<< "+----+----+------+-------------------------------------" << endl;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return "No images currently attached.\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < devices.devices_size() ; i++) {
|
|
|
|
PbDevice device = devices.devices(i);
|
|
|
|
|
2021-08-08 17:08:58 +02:00
|
|
|
s << "| " << device.id() << " | " << device.un() << " | " << MapTypeToId(device.type()) << " | "
|
|
|
|
<< (device.file().empty() ? "NO MEDIA" : device.file())
|
|
|
|
<< (device.read_only() ? " (WRITEPROTECT)" : "") << endl;
|
2021-07-19 00:15:13 +02:00
|
|
|
}
|
|
|
|
|
2021-07-24 02:13:05 +02:00
|
|
|
s << "+----+----+------+-------------------------------------" << endl;
|
2021-07-19 00:15:13 +02:00
|
|
|
|
2021-07-24 02:13:05 +02:00
|
|
|
return s.str();
|
2021-07-19 00:15:13 +02:00
|
|
|
}
|
2021-08-08 17:08:58 +02:00
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Map the device ID to the PbDeviceType and vice versa
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
PbDeviceType MapIdToType(const string& id, bool is_sasi)
|
|
|
|
{
|
|
|
|
if (id == "SCHD") {
|
|
|
|
return is_sasi ? SASI_HD : SCSI_HD;
|
|
|
|
}
|
|
|
|
else if (id == "SCMO") {
|
|
|
|
return MO;
|
|
|
|
}
|
|
|
|
else if (id == "SCCD") {
|
|
|
|
return CD;
|
|
|
|
}
|
|
|
|
else if (id == "SCBR") {
|
|
|
|
return BR;
|
|
|
|
}
|
|
|
|
else if (id == "SCDP") {
|
|
|
|
return DAYNAPORT;
|
|
|
|
}
|
2021-08-10 01:56:13 +02:00
|
|
|
else if (id == "SCNL") {
|
|
|
|
return NUVOLINK;
|
|
|
|
}
|
2021-08-08 17:08:58 +02:00
|
|
|
else {
|
|
|
|
return UNDEFINED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
string MapTypeToId(const PbDeviceType type)
|
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case SASI_HD:
|
|
|
|
case SCSI_HD:
|
|
|
|
return "SCHD";
|
|
|
|
|
|
|
|
case MO:
|
|
|
|
return "SCMO";
|
|
|
|
|
|
|
|
case CD:
|
|
|
|
return "SCCD";
|
|
|
|
|
|
|
|
case BR:
|
|
|
|
return "SCBR";
|
|
|
|
|
|
|
|
case DAYNAPORT:
|
|
|
|
return "SCDP";
|
|
|
|
|
2021-08-10 01:56:13 +02:00
|
|
|
case NUVOLINK:
|
|
|
|
return "SCNL";
|
|
|
|
|
2021-08-08 17:08:58 +02:00
|
|
|
default:
|
|
|
|
return "????";
|
|
|
|
}
|
|
|
|
}
|