#ifndef LIBFTFAKE_HL_H_ #define LIBFTFAKE_HL_H_ #include #define WARNSTR "\x1b[1;31mW:\x1b[0m " __attribute__((__packed__)) struct settings { uint8_t norm_or_pwIsMicrosec; uint8_t clockfreq[2]; uint8_t pw_trigscale[2]; uint8_t ms1[3]; uint8_t ms2[3]; uint8_t ms3_ioflg[3]; uint8_t unk00; uint8_t ntrigsteps; uint8_t unkf0; uint8_t unk0f; uint8_t capgenchans; uint8_t voltage[2]; uint8_t unk32; uint8_t nabort; uint8_t abort; }; struct trigstep_nice { bool ch_ignore[4]; bool use_max_pw, use_min_pw; bool ch_hiri1_lofa0[4]; bool level1_edge0; uint16_t pw_min, pw_max; bool unkB2b3, unkB2b4, unkB3b6; // bit index: bytevalofsinglebit = 1< 0x20) { gensize += len; return; } else { printf("\tgenerate size: 0x%zx\n", gensize); state_tonorm(); } } switch (buf[0]) { case 0x93:printf("\t->application\n");break; case 0x94:printf("\t->bootloader\n");break; case 0xf0: switch (buf[1]) { case 0x00:printf("\tcapture reset\n");break; case 0x01: printf("\tstart capt/WFT\n"); state = scwftres3; break; case 0x02:printf("\tsiggen start repeat\n");break; case 0x03: printf("\tmixed-mode sfc/wft\n"); state=scwftres3; break; case 0x05: printf("\tstart gendata dl\n"); if (buf[2]!=0xf3)printf("\t" WARNSTR "unk arg2 0x%02x\n", buf[2]); state = ingenupload; gensize = 0; break; case 0x06: printf("\tstart read\n"); state = incapreadout; capsize = 0; break; case 0x07:printf("\tsiggen start once\n");break; default:printf("\t" WARNSTR "unk 0xf0 arg 0x%02x!\n", buf[1]); } break; break; case 0xf1: if (len == 27) { printf("\teep magic 0x%02x 0x%02x 0x%02x\n", buf[1],buf[2],buf[3]); } else if (len == 25) { struct settings sett = *(struct settings*)&buf[1]; // hacks bool weird = sett.unk00 != 0x00 || sett.unkf0 != 0xf0 || sett.unk0f != 0x0f || sett.unk32 != 0x32 || sett.nabort != 0x01 || sett.abort != 0x00 || (sett.capgenchans&0xf)!=0xf || (sett.norm_or_pwIsMicrosec != 0x09 && sett.norm_or_pwIsMicrosec != 0x01); uint8_t ioflg = sett.ms3_ioflg[2] & 0xf0; // MSB high nibble ORed with the inverse of nibble M at loc 0x12 if (((uint8_t)ioflg ^ (uint8_t)(sett.capgenchans & 0xf0)) != 0xf0) weird = true; float freq = 100000.0f / *(uint16_t*)&sett.clockfreq[0]; char normpw = '?'; if (sett.norm_or_pwIsMicrosec == 0x09) normpw = 'P'; if (sett.norm_or_pwIsMicrosec == 0x01) normpw = 'n'; uint32_t ms1 = *(uint32_t*)&sett.ms1[0] & 0x00ffffff; uint32_t ms2 = *(uint32_t*)&sett.ms2[0] & 0x00ffffff; uint32_t ms3 = *(uint32_t*)&sett.ms3_ioflg[0] & 0x000fffff; printf("\t%ssettings:\n", weird ? WARNSTR : ""); printf("\t freq=%d kHz #tsteps=%hhu trigscale=0x%04x pwmicro=%c genmap=%c%c%c%c:%x(%x)\n", (int)freq, sett.ntrigsteps, *(uint16_t*)&sett.pw_trigscale[0], normpw, (sett.capgenchans & 0x10)?'1':'-', (sett.capgenchans & 0x20)?'2':'-', (sett.capgenchans & 0x40)?'3':'-', (sett.capgenchans & 0x80)?'4':'-', sett.capgenchans&0xf,ioflg>>4 ); printf("\t ms1=0x%06x ms2=0x%06x ms3=0x%06x\n", ms1, ms2, ms3); float volt = 0.1f*roundf((sett.voltage[0] / 39.2f) * 10.0f); printf("\t voltage=%.1f unk00=%x unkf0=%02x unk0f=%02x unk32=%02x nabort=%x abort=%x\n", volt, sett.unk00, sett.unkf0, sett.unk0f, sett.unk32, sett.nabort, sett.abort); } else { printf("\t" WARNSTR "0xF1 formatting unknown!\n"); } break; case 0xf4: { size_t nst = (len - 1) >> 2; printf("\ttrigger: %zu steps\n", nst); for (size_t i = 0; i < nst; ++i) { size_t ind = 1 + i * 4; struct trigstep_nice step; step.ch_ignore[0] = buf[ind+0] & 0x40; step.ch_ignore[1] = buf[ind+0] & 0x80; step.ch_ignore[2] = buf[ind+1] & 0x01; step.ch_ignore[3] = buf[ind+1] & 0x02; step.use_max_pw = !(buf[ind+0] & 0x20); step.use_min_pw = !(buf[ind+0] & 0x10); step.ch_hiri1_lofa0[0] = buf[ind+0] & 0x01; step.ch_hiri1_lofa0[1] = buf[ind+0] & 0x02; step.ch_hiri1_lofa0[2] = buf[ind+0] & 0x04; step.ch_hiri1_lofa0[3] = buf[ind+0] & 0x08; step.pw_min = ((buf[ind+1] & 0xf8) >> 3) | ((uint16_t)(buf[ind+2] & 0x07) << 5); step.pw_max = ((buf[ind+2] & 0xe0) >> 5) | ((uint16_t)(buf[ind+3] & 0x3f) << 3); step.level1_edge0 = buf[ind+3] & 0x80; step.unkB2b3 = buf[ind+2] & (1<<3); step.unkB2b4 = buf[ind+2] & (1<<4); step.unkB3b6 = buf[ind+3] & (1<<6); printf("\t"); if (step.unkB2b3 || step.unkB2b4 || step.unkB3b6) printf(WARNSTR); printf(" chans %c%c%c%c :: %s %s %s %s %s minpw=%d maxpw=%d", (step.ch_ignore[0]?'-':'1'), (step.ch_ignore[1]?'-':'2'), (step.ch_ignore[2]?'-':'3'), (step.ch_ignore[3]?'-':'4'), (step.ch_ignore[0]?"-":(step.ch_hiri1_lofa0[0]?"hiri":"lofa")), (step.ch_ignore[1]?"-":(step.ch_hiri1_lofa0[1]?"hiri":"lofa")), (step.ch_ignore[2]?"-":(step.ch_hiri1_lofa0[2]?"hiri":"lofa")), (step.ch_ignore[3]?"-":(step.ch_hiri1_lofa0[3]?"hiri":"lofa")), step.level1_edge0 ? "level" : "edge", step.use_min_pw ? (int)step.pw_min : (-1), step.use_max_pw ? (int)step.pw_max : (-1) ); if (step.unkB2b3) printf(" uB2b3!"); if (step.unkB2b4) printf(" uB2b4!"); if (step.unkB3b6) printf(" uB3b6!"); printf("\n"); } } break; case 0xfd:printf("\techo status\n");break; default: printf("\t" WARNSTR "unknown command 0x%02x!\n", buf[0]); break; } } static void ftfake_cb(void* buf_, size_t len) { uint8_t* buf = (uint8_t*)buf_; switch (state) { case incapreadout: capsize += len; break; /*case ingenupload: gensize += len; break;*/ case scwftres3: { uint32_t trig_instant = (uint32_t)buf[0] | ((uint32_t)buf[1] << 8) | ((uint32_t)buf[2]<<16); printf("\ttrig_instant=0x%06x\n", trig_instant); ++state; // to scfwres1 } break; case scwftres1: printf("\t%sscwftres = 0x%02x\n", (buf[0] == 0xdd ? "" : WARNSTR), buf[0]); state_tonorm(); break; default: break; } } #endif