-
Notifications
You must be signed in to change notification settings - Fork 0
/
responder.cpp
129 lines (124 loc) · 4.06 KB
/
responder.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include "responder.hpp"
#include <iostream>
#include <errno.h> // errno
#include <string.h> // strerror
using namespace std;
using namespace hwitl;
Responder::CallbackEntry Responder::getRegisteredCallback(hwitl::Address target) {
//cout << hex << "Callback target: 0x" << target << endl;
for(const auto& entry : registeredRanges) {
//cout << "from 0x" << hex << entry.range.from << " to 0x" << entry.range.to << dec << endl;
if(entry.range.from <= target && entry.range.to > target) {
return entry;
}
}
//cout << "Callback not found" << endl;
return Responder::CallbackEntry{{0,0},nullptr,nullptr};
}
void Responder::addCallback(CallbackEntry callback) {
if(!isAddressRangeValid(callback.range)) {
cerr << "Callback bad" << endl;
return;
}
registeredRanges.emplace_front(callback);
}
void Responder::listener() {
cout << "[responder] listening" << endl;
while(m_handle) {
static_assert(sizeof(Request::Command) == 1);
Request::Command command;
if(!readStruct(m_handle, command)) {
cerr << "[responder] error reading request" << endl;
return;
}
ResponseStatus stat(ResponseStatus::Ack::ok, irq_active);
switch(command) {
case Request::Command::reset:
// No response!
break;
case Request::Command::getIRQ:
if(!writeStruct(m_handle, stat)) {
cerr << "[responder] error writing keepalive" << strerror(errno) << endl;
}
break;
case Request::Command::exit:
cerr << "graceful exit" << endl;
return;
case Request::Command::read:
{
Address raw_addr;
if(!readStruct(m_handle, raw_addr)) {
cerr << "[responder] error reading read request" << strerror(errno) << endl;
return;
}
const auto read = RequestRead::fromNetwork(raw_addr);
const auto targetAddress = read.request.getAddressToHost();
auto callback = getRegisteredCallback(targetAddress);
const bool is_mapped = isAddressRangeValid(callback.range);
Payload payload = 0;
if(!is_mapped) {
cerr << "Callback on address 0x" << hex << targetAddress << dec << " not mapped" << endl;
stat.ack = ResponseStatus::Ack::not_mapped;
} else {
if(!callback.read) {
cerr << "Callback on address 0x" << hex << targetAddress << dec << " not readable" << endl;
stat.ack = ResponseStatus::Ack::command_not_supported;
} else {
payload = callback.read(targetAddress);
}
}
ResponseRead response(stat, payload);
if(!writeStruct(m_handle, response)) {
cerr << "[responder] error writing response read" << strerror(errno) << endl;
}
}
break;
case Request::Command::write:
{
Address raw_addr;
if(!readStruct(m_handle, raw_addr)) {
cerr << "[responder] error reading write request" << strerror(errno) << endl;
return;
}
Payload raw_payload;
if(!readStruct(m_handle, raw_payload)){
cerr << "[responder] error reading write payload" << strerror(errno) << endl;
return;
}
const auto write = RequestWrite::fromNetwork(raw_addr, raw_payload);
const auto targetAddress = write.m_request.getAddressToHost();
auto callback = getRegisteredCallback(targetAddress);
const bool is_mapped = isAddressRangeValid(callback.range);
ResponseStatus stat(ResponseStatus::Ack::ok, irq_active);
if(!is_mapped) {
cerr << "Callback on address 0x" << hex << targetAddress << dec << " not mapped" << endl;
stat.ack = ResponseStatus::Ack::not_mapped;
} else {
if(!callback.write) {
cerr << "Callback on address 0x" << hex << targetAddress << dec << " not writable" << endl;
stat.ack = ResponseStatus::Ack::command_not_supported;
} else {
callback.write(targetAddress, write.getPayload());
}
}
ResponseWrite response{stat};
if(!writeStruct(m_handle, response)) {
cerr << "[responder] error writing response write" << strerror(errno) << endl;
}
}
break;
default:
{
stat.ack = ResponseStatus::Ack::command_not_supported;
ResponseWrite response{stat};
if(!writeStruct(m_handle, response)) {
cerr << "[responder] error writing response write" << strerror(errno) << endl;
}
}
return;
}
}
}
void Responder::setIRQ(bool active) {
irq_active = active;
}