aboutsummaryrefslogtreecommitdiff
path: root/src/modules/bt_cfg/at.hpp
blob: 7616c6a4ef6a8be29d032242cebf90b243bc6d1a (plain) (blame)
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#pragma once

#include <unistd.h>

#include <cstdlib>
#include <cstring>

// #include <algorithm>
// #include <iterator>
#include <utility>

// #include "string_algorithms.hpp"

namespace AT {

constexpr size_t reply_buffer_size = 128;
constexpr size_t reply_read_retries = 25;
constexpr useconds_t reply_read_delay = 100 * 1000;

// template <typename ForwardIt>
// std::pair<bool, bool> // ok/err received, it was ok
// check_reply_ok_err(ForwardIt first, ForwardIt last) {
// 	bool found = false;
// 	bool ok = false;
// 	if (first != last) {
// 		auto crlf = find_crlf(first, last);
// 		while (crlf != last) {
// 			auto dist = std::distance(first, crlf);
// 			ok = dist == 2 and std::equal(first, crlf, "OK");
// 			found = ok or (dist == 5 and std::equal(first, crlf, "ERROR"));
//
// 			if (found) break;
//
// 			std::advance(crlf, 2);
// 			first = crlf;
// 			crlf = find_crlf(first, last);
// 		}
// 	}
// 	return std::make_pair(found, ok);
// }
//
// template <typename Device>
// std::pair<bool, bool> // ok/err received, it was ok
// wait_ok_error(Device &f) {
// 	auto retries = reply_read_retries;
// 	bool found = false;
// 	bool ok = false;
// 	char buf[reply_buffer_size];
// 	ssize_t s = 0, n = 0;
// 	usleep(reply_read_delay);
// 	while (not found || retries > 0) {
// 		s = read(f, buf + n, sizeof(buf) - n);
// 		if (s < 0) break;
// 		if (s == 0) {
// 			usleep(reply_read_delay);
// 			--retries;
// 			s = read(f, buf + n, sizeof(buf) - n);
// 			if (s <= 0) break;
// 		}
// 		n += s;
// 		std::tie(found, ok) = check_reply_ok_err(buf, buf + n);
// 	}
// 	if (not found and n > 0)
// 		std::tie(found, ok) = check_reply_ok_err(buf, buf + n);
// 	return std::make_pair(found, ok);
// }

template <typename Device>
std::pair<bool, bool> // ok/err received, it was ok
wait_ok_error(Device &f) {
	auto retries = reply_read_retries;
	bool found = false;
	bool ok = false;
	char buf[reply_buffer_size + 1];
	ssize_t s = 0;
       	size_t n = 0;
	usleep(reply_read_delay);
	while (not found || retries > 0) {
		s = read(f, buf + n, reply_buffer_size - n);
		if (s < 0) break;
		if (s == 0) {
			usleep(reply_read_delay);
			--retries;
			s = read(f, buf + n, reply_buffer_size - n);
			if (s <= 0) break;
		}
		n += s;
		buf[n] = '\0';
		ok = std::strstr(buf, "\r\nOK\r\n");
		found = ok or std::strstr(buf, "\r\nERROR\r\n");
	}
	if (not found and n > 0) {
		buf[n] = '\0';
		ok = std::strstr(buf, "\r\nOK\r\n");
		found = ok or std::strstr(buf, "\r\nERROR\r\n");
	}
	return std::make_pair(found, ok);
}

template <typename Device>
inline bool
write_char(Device &f, char ch) {
	return write(f, &ch, 1) == 1;
}

template <typename Device>
inline bool
exec_cmd(Device &f, const char cmd[], std::size_t len) {
	return write(f, cmd, len) == len and write_char(f, '\r')
		and wait_ok_error(f).second;
}

template <typename Device>
inline bool
exec_cmd(Device &f, const char * const cmd) {
	return exec_cmd(f, cmd, std::strlen(cmd));
}

template <typename Device>
inline bool
exec_reset(Device &f) {
	static const char at_reset[] = "AT*AMWS=0,0,0,0,1,0";
	const ssize_t len = sizeof(at_reset) - 1;
	bool ok = write(f, at_reset, len) == len and write_char(f, '\r');
	if (ok) sleep(1);
	return ok;
}

template <typename Device>
inline bool
switch_to_at_mode(Device &f) {
	sleep(1);
	static const char escape_seq[3] = {'/', '/', '/'};
	bool ok = write(f, escape_seq, sizeof(escape_seq));
	if (ok) {
		sleep(1);
		ok = exec_cmd(f, "AT");
	}
	return ok;
}

template <typename Device>
inline bool
switch_to_data_mode(Device &f) {
	return exec_cmd(f, "AT*ADDM");
}

} // end of namespace AT