18#include <radio_tool/fw/tyt_fw_sgl.hpp>
19#include <radio_tool/util.hpp>
26constexpr auto HeaderLen = 0x400u;
27constexpr auto Header1Len = 0x10u;
28constexpr auto Header2Len = 0x67u;
30constexpr auto BinaryLenOffset = 0x06;
31constexpr auto GroupOffset = 0x32;
32constexpr auto ModelOffset = GroupOffset + 0x10;
33constexpr auto VersionOffset = ModelOffset + 0x08;
34constexpr auto KeyOffset = 0x5f;
38 auto hdr = ReadHeader(file);
40 for (
const auto& cfg : tyt::config::sgl::All) {
41 if (cfg.header.radio_group == hdr.radio_group) {
42 config =
new TYTSGLRadioConfig(cfg.radio_model, hdr, cfg.cipher, cfg.cipher_len, cfg.xor_offset);
47 if (config ==
nullptr) {
48 std::stringstream msg;
49 msg <<
"Radio model '" << hdr.radio_group <<
"' not supported!";
51 throw std::runtime_error(msg.str());
54 auto i = std::ifstream(file, std::ios_base::binary);
57 i.seekg(0x400, i.beg);
58 i.seekg(hdr.binary_offset, i.cur);
60 data.resize(hdr.length);
61 i.read((
char*)data.data(), hdr.length);
63 memory_ranges.push_back(std::pair<uint32_t, uint32_t>(0, data.size()));
70 if (config ==
nullptr) {
71 throw std::runtime_error(
"No header set, cannot write firmware");
73 if (config->header.length != data.size()) {
74 throw std::runtime_error(
"Binary size mismatch, size in header does not match actual binary length");
77 std::ofstream fout(file, std::ios_base::binary);
80 auto header = config->header.Serialize();
81 fout.write((
char*)header.data(), header.size());
82 fout.write((
char*)data.data(), data.size());
89 if (config ==
nullptr) {
90 throw std::runtime_error(
"No header set, cannot print firmware info");
93 std::stringstream out;
94 out <<
"== TYT SGL Firmware == " << std::endl
96 << config->
header.ToString() << std::endl
97 <<
"Data Segments: " << std::endl;
101 out <<
" " << n++ <<
": Length=0x" << std::setfill(
'0') << std::setw(8) << std::hex << m.second
110 i.open(file, i.binary);
113 uint8_t header1[Header1Len];
114 i.read((
char*)header1, Header1Len);
116 if (!std::equal(header1, header1 + 4, tyt::config::sgl::Magic.begin()))
118 throw std::runtime_error(
"Invalid SGL header magic");
121 for (
auto x = 4;x < Header1Len;x++) {
122 header1[x] ^= tyt::config::sgl::Magic[x % 4];
125 auto sgl_version = std::stoi((
char*)header1 + 9);
126 if (sgl_version != 1) {
127 std::stringstream msg(
"Invalid SGL version: ");
129 throw std::runtime_error(msg.str());
132 auto header2_offset = *(uint16_t*)(header1 + 12);
134 i.seekg(header2_offset, i.beg);
135 uint8_t header2[Header2Len];
136 i.read((
char*)header2, Header2Len);
138 auto h2_xor = header1 + 14;
139 for (
auto x = 0;x < Header2Len;x++) {
140 header2[x] ^= h2_xor[x % 2];
143 auto binary_offset = header1[11];
144 auto len = *(uint32_t*)(header2 + BinaryLenOffset);
145 auto group = std::string(header2 + GroupOffset, header2 + GroupOffset + 0x10);
146 auto model = std::string(header2 + ModelOffset, header2 + ModelOffset + 0x08);
147 auto version = std::string(header2 + VersionOffset, header2 + VersionOffset + 0x08);
148 auto key = std::string(header2 + KeyOffset, header2 + KeyOffset + 0x08);
150 return SGLHeader(sgl_version, len, group, model, version, key, binary_offset, header2_offset);
154 throw std::runtime_error(
"Can't open firmware file");
162 auto header = ReadHeader(file);
163 if (header.length != 0)
168 catch (std::exception e) {
169 std::cerr << e.what() << std::endl;
176 for (
const auto& mx : tyt::config::sgl::All)
178 if (mx.radio_model == model)
188 if (config ==
nullptr) {
189 throw std::runtime_error(
"Radio model not selected");
196 for (
const auto& rg : tyt::config::sgl::All)
198 if (rg.radio_model == model)
200 config =
new TYTSGLRadioConfig(rg.radio_model, rg.header.AsNew(data.size()), rg.cipher, rg.cipher_len, rg.xor_offset);
209 for (
auto& dx : data)
211 dx = ~(((dx << 3) & 0b11111000) | ((dx >> 5) & 0b00000111));
212 dx = dx ^ config->cipher[(config->xor_offset + cx++) % config->cipher_len];
222 if (data.size() < config->header.length)
224 std::fill_n(std::back_inserter(data), config->header.length - data.size(), 0xff);
228 for (
auto& dx : data)
230 dx = dx ^ config->cipher[(config->xor_offset + cx++) % config->cipher_len];
231 dx = ~(((dx >> 3) & 0b00011111) | ((dx << 5) & 0b11100000));
237 if (
typeid(other) !=
typeid(
TYTSGLFW)) {
241 if (config ==
nullptr) {
242 throw std::runtime_error(
"Header is not loaded, cannot compare firmware support");
245 auto fw =
dynamic_cast<const TYTSGLFW*
>(other);
247 && fw->config->radio_model == config->radio_model;
250auto SGLHeader::ToString() const -> std::
string
252 std::stringstream ss;
254 ss <<
"SGL version: " << sgl_version << std::endl
255 <<
"Length: " << length << std::endl
256 <<
"Radio Group: " << radio_group << std::endl
257 <<
"Model: " << radio_model << std::endl
258 <<
"Protocol Version: " << protocol_version << std::endl
259 <<
"Key: " << model_key << std::endl
260 <<
"Binary Offset: 0x400 + 0x" << std::hex << std::setw(2) << std::setfill(
'0') << (int)binary_offset;
267 std::default_random_engine eng;
270 std::uniform_int_distribution<uint16_t> model_key_dist(
'!',
'}');
271 auto new_model_key = std::vector<uint8_t>{
272 (uint8_t)model_key[0],
273 (uint8_t)model_key[1],
274 (uint8_t)model_key[2],
275 (uint8_t)model_key[3],
276 (uint8_t)model_key_dist(eng),
277 (uint8_t)model_key_dist(eng),
278 (uint8_t)model_key_dist(eng),
279 (uint8_t)model_key_dist(eng)
283 std::uniform_int_distribution<uint16_t> binary_offset_dist(0, 0x80);
284 auto new_binary_offset = binary_offset_dist(eng);
287 std::uniform_int_distribution<uint16_t> h2_offset_dist(0x1e, 0x100);
288 auto new_h2_offset = h2_offset_dist(eng);
290 return SGLHeader(sgl_version, binary_len, radio_group, radio_model, protocol_version, std::string(new_model_key.begin(), new_model_key.end()), new_binary_offset, new_h2_offset);
293auto SGLHeader::Serialize(
bool encrypt)
const -> std::vector<uint8_t>
295 auto header = std::vector<uint8_t>(HeaderLen + binary_offset);
298 std::copy(tyt::config::sgl::Magic.begin(), tyt::config::sgl::Magic.end(), header.begin());
301 std::stringstream ss_version;
302 ss_version <<
"ENCV" << std::setw(3) << std::setfill(
'0') << sgl_version;
303 auto version = ss_version.str();
304 std::copy(version.begin(), version.end(), header.begin() + 4);
307 *(header.data() + 11) = binary_offset;
310 *(uint16_t*)(header.data() + 12) = header2_offset;
313 auto h2_key_offset = 14;
314 std::default_random_engine eng;
315 std::uniform_int_distribution<uint16_t> dist(0, 0xffff);
316 auto key = dist(eng);
317 *(uint16_t*)(header.data() + h2_key_offset) = key;
319 auto h2 = header.data() + header2_offset;
324 *(uint32_t*)(h2 + BinaryLenOffset) = length;
326 std::copy(radio_group.begin(), radio_group.end(), h2 + GroupOffset);
327 std::copy(radio_model.begin(), radio_model.end(), h2 + ModelOffset);
328 std::copy(protocol_version.begin(), protocol_version.end(), h2 + VersionOffset);
329 std::copy(model_key.begin(), model_key.end(), h2 + KeyOffset);
333 auto h2_key = (uint8_t*)(header.data() + h2_key_offset);
334 for (
auto h2x = 0;h2x < Header2Len;h2x++) {
335 *(h2 + h2x) ^= h2_key[h2x % 2];
339 for (
auto h1x = 4;h1x < Header1Len;h1x++) {
340 *(header.data() + h1x) ^= tyt::config::sgl::Magic[h1x % 4];
349 return other.length == length
350 && other.sgl_version == sgl_version
351 && other.protocol_version == protocol_version
352 && std::equal(other.model_key.begin(), other.model_key.begin() + 4, model_key.begin())
353 && other.radio_group == radio_group
354 && other.radio_model == radio_model;