public static async Task <Codeplug> ReadFromRadio(string comPort, IProgress <string> progress = null) { Codeplug codeplug = null; await Task.Run(() => { try { using var com = new Com(comPort); com.StatusUpdate += (s, e) => progress?.Report(e.Status); com.EnterProgrammingMode(); var firmwareVersion = com.GetFirmwareVersion(); var extStartBytes = com.Read(0x0002, 0x02); var extStart = extStartBytes[0] * 0x100 + extStartBytes[1]; var lengthBytes = com.Read(extStart + 0x26, 0x02); //Calculate total bytes to read from 0x0000 to end of External Codeplug var length = extStart + (lengthBytes[0] * 0x100 + lengthBytes[1]); var codeplugBytes = new byte[length]; for (int i = 0; i < length; i += 0x20) { var bytesToRead = Math.Min(0x20, length - i); com.Read(i, bytesToRead, codeplugBytes); } codeplug = new Codeplug(codeplugBytes); codeplug.Model = Common.GetModel(codeplug.InternalCodeplug.Model); codeplug.Firmware = Common.GetFirmware(firmwareVersion); codeplug.FactoryCode = com.Read(0x81F0, 0x10); com.ExitSbepMode(); AuthCode.Calculate(codeplug); File.WriteAllBytes(codeplug.GetProposedFileName(), codeplugBytes); } catch (Exception e) { if (progress != null) { progress.Report($"\r\n\r\nOperation Failed!\r\n\r\n{e.Message}"); } else { throw; } } }).ConfigureAwait(false); return(codeplug); }
public static void Calculate(Codeplug codeplug) { var signatureBytes = codeplug.Firmware.SignatureBytes; if (signatureBytes == null || signatureBytes.Length == 0) { codeplug.AuthCodeStatus = $"Unknown Firmware Version {codeplug.Firmware.Version:0.00}. Firmware must be read in Flash Mode to get the bytes required for the calculation."; return; } byte[] buffer = new byte[0x50]; Encoding.ASCII.GetBytes(codeplug.InternalCodeplug.Model).CopyTo(buffer, MODEL); //Calculate Factory Code Bytes 7 and 8 //These bytes are calculated by the official process and already stored in flash. //Codeplug has the same series of bytes, except for bytes 7 and 8 are 0x00; //Seems to just really be a checksum var fc = codeplug.FactoryCode; var check = (fc[0x0] * 0x100 + fc[0x1]) + (fc[0x2] * 0x100 + fc[0x3]) + (fc[0x4] * 0x100 + fc[0x5]) + (fc[0x8] * 0x100 + fc[0x9]) + (fc[0xA] * 0x100 + fc[0xB]) + (fc[0xC] * 0x100 + fc[0xD]) + (fc[0xE] * 0x100 + fc[0xF]); check = ~((check & 0xFFFF) - 0xFFF8) + 1; fc[0x6] = (byte)(check / 0x100); fc[0x7] = (byte)(check % 0x100); fc.CopyTo(buffer, FACTORY_CODE); signatureBytes.CopyTo(buffer, FLASH_SIGNATURE); codeplug.InternalCodeplug.Block10.FeatureBlock.CopyTo(buffer, FDB_PART_A); codeplug.InternalCodeplug.Block10.Flashcode.CopyTo(buffer, FDB_PART_B); byte[] authCode = new byte[10]; var i = 0; var j = 0; byte z = 0; foreach (byte o in ORDER) { byte a = buffer[o]; a ^= z; //eora byte_70 z = a; //staa byte_70 a = (byte)((sbyte)(a) >> 1); //asra ;Arithmetic Shift Right a = (byte)(a >> 1); //lsra ;Logical Shift Right a ^= z; //eora byte_70 byte b = a; //tab a = (byte)(a << 1); //asla (or lsla) ;Logical Shift Left a &= 0xF0; //anda #$F0 b = (byte)((sbyte)(b) >> 1); //asrb ;Arithmetic Shift Right if ((b & 0x80) == 0x80) //bmi ;Is MSB (aka Negative Bit) Set? { b = (byte)(~b); //comb } b &= 0x0f; //andb #$F a = (byte)(a + b); //aba b = z; //ldab byte_70 b &= 0x7; //andb #7 a ^= KEY[b]; //ldx #$D8B9 -- abx -- eora 0,x z = a; //staa byte_70 if (++i % 8 == 0) { authCode[j++] = z; z = 0; } } byte[] serial = Encoding.ASCII.GetBytes(codeplug.InternalCodeplug.Serial); for (int x = 0; x < 10; x++) { authCode[x] = (byte)(authCode[x] ^ serial[x]); } codeplug.CalculatedAuthCode = authCode; if (authCode.SequenceEqual(codeplug.InternalCodeplug.AuthCode)) { codeplug.AuthCodeStatus = "Successfully calculated matching auth code."; } else { codeplug.AuthCodeStatus = "Not able to calculate existing auth code. If radio is showing 01/93 error, the calculated code should be written to the radio to fix this error."; } }