Agilent N9340B and N9340C license generatorFor all owners of this Agilent HSA, here is a quick vacation gift (created in less than 1 hour between some pool dives
).
The code is C# but should be totally self-explanatory.
private static void calc_license_Agilent_N9340B_C(string hostID, bool is_N9340C)
{
string[] option = { "PA3", "TG3", "SO3", "DMA", "AMA", "DFS", "KLS", "IBC", "IBF",
"INM", "XDM", "BAS", "PAK", "SEM", "SPT", "PWM", "MKT", "U01" };
if (hostID.Length != 8)
Console.WriteLine("Error in hostID length!");
for (int m = 0; m < option.Length; m++)
{
byte[] hash = MD5.Create().ComputeHash(Encoding.ASCII.GetBytes(hostID + option[m] + (is_N9340C ? "DFE" : "")));
Console.Write("{0,-2} {1} ", m, option[m]);
for (int i = 0; i < hash.Length; i++)
{
byte c = 0;
for (int j = 0; j < 8; j++)
c += (byte)(hash[i] ^ hostID[j]);
c = (byte)(c % 36 + 48);
if (c > 57)
c += 7;
Console.Write(Convert.ToChar(c));
}
Console.WriteLine();
}
}
EDIT March 30th, 2023: Added the generation of N9340C family licenses. List of options is
here.
I can confirm that using writeoption(x,0) gives a permanent license.
Make sure you reboot the unit after enabling the new option.
yes, that works
but did you dare to try SO3 option? does it work?
I already had the TG3 on mine and added the two remaining official options DMA and AMA. Didn't want to risk it with unofficial options.
To remove the options:
That is achieved by running function s_remoteoptionclear which is called by a SCPI command. ATM, don't know the syntax of the command.
To remove the options:
That is achieved by running function s_remoteoptionclear which is called by a SCPI command. ATM, don't know the syntax of the command.
it would be very handy to have a way of removing options. I saw this function in the code but cannot figure out how/where to call it.
Try this command:
REMOTE:OPTION:CLEAR
created in less than 1 hour between some pool dives
Same "mode of operation" here. If you've seen a guy paddling on a SUP board near address 0x8BED0 - that was me
Invoking s_remoteoptionclear() without parameters in the shell should clear all options.
Btw, there is a full set of SCPI commands under REMOTE:OPTION to query/add/delete options. One idea why "REMOTE:OPTION:CLEAR" didn't worked: the "CLEAR" part is written as "CLEAr" in the binary, maybe it is case sensitive? Does SCPI work at all? Any reply from *IDN? command? (Just in case: these are NOT shell commands, but SCPI).
Btw, there is a full set of SCPI commands under REMOTE:OPTION to query/add/delete options. One idea why "REMOTE:OPTION:CLEAR" didn't worked: the "CLEAR" part is written as "CLEAr" in the binary, maybe it is case sensitive? Does SCPI work at all? Any reply from *IDN? command? (Just in case: these are NOT shell commands, but SCPI).
The CLEAr only means that you can use also the CLEA version. But, full uppercase should work as in almost all equipments, as the programs usually convert the full string to uppercase before processing.
Have you found a way to extract the SCPI command tree?
HostID is similarly calculated from the last 8 digits of the Digital Module S/N.
created in less than 1 hour between some pool dives
Same "mode of operation" here. If you've seen a guy paddling on a SUP board near address 0x8BED0 - that was me
Invoking s_remoteoptionclear() without parameters in the shell should clear all options.
Btw, there is a full set of SCPI commands under REMOTE:OPTION to query/add/delete options. One idea why "REMOTE:OPTION:CLEAR" didn't worked: the "CLEAR" part is written as "CLEAr" in the binary, maybe it is case sensitive? Does SCPI work at all? Any reply from *IDN? command? (Just in case: these are NOT shell commands, but SCPI).
I'll try this later today but isn't there any way to remove one particular option. perhaps by directly manipulating a memory location in flash
by "sysFlashSet"
sysFlashSet("111", 4, 0x3202BC+4*option_index) should do the job.
I've suggested using a raw address 0xC0001000 instead of "111" earlier (in PM), that's ok too (just need any valid pointer to some data that DOESN'T look like a valid option flag), but IIRC VxWorks shell allows to pass strings for pointer args (it stores them in a temporary buffer and passes correct pointers).
You can check the flash contents before writing with a command like: d 0x903202BC,4
An active option should have byte0!=FF, byte1!=FF, byte2 = byte0 XOR byte1
Note the difference in addresses: 0x90xxxxxx address for "d" command is an absolute address ("d" is not flash-specific), but sysFlashSet() expect an offset from flash base (0x90000000) and adds the base internally.
Option-related addresses:
0x903202BC: byte activation_flags[18][4] - [2] = [0] ^ [1] means "installed"
0x90322000: byte installed_keys[18][20] - key strings (for display, never checked once installed)
0x90322260: uint64 expiration_dates[18] - expiration dates in Unix format
The CLEAr only means that you can use also the CLEA version.
One suspicious thing: there is a table of long and short forms at SCPIstr (format is { char long[15], short[6] }) and there are two separate entries for "CLEAR":
long="CLEAR", short="CLE"
long="CLEAr", short="CLEA"
All other commands have both forms in uppercase. Since the tree (at StateP) is defined as indices into this array, these two entries will have different meanings.
Since the tree (at StateP) is defined as indices into this array, these two entries will have different meanings.
Can you exemplify the indices into the array?
The correct cmd is DEBUG:REMOTE:OPTION:CLEAR
The tree structure:
StateP: array of pointers to arrays of { u8 str_idx, u8, u16 next_state_idx, u16 func_idx }
str_idx is an index into SCPIstr array of { char long[15], short[6] }
str_idx==0xFF - last entry
next_state_idx is an index into StateP[]
func_idx is an index to FunSP[]
"st_main" is the root state
The parser starts with current_state = 0 (StateP[0] -> st_main), compares the current cmd part with all SCPIstr[StateP[i++].str_idx].long/.short until match, then sets current_state = next_state_idx
If next_state_idx==0 - this is the last token in chain, invoke the function FunSP[func_idx]
Going to code an IDA script to extract a full list
The tree structure:
Excellent job! I'll also add to my parser.
PS: Did you got off the SUP for this one?
PS1: I think:
{
u8 str_idx, u8, u16 next_state_idx, u16 func_idx }
is
{
u16 str_idx, u16 next_state_idx, u16 func_idx }
PS1: I think:
{ u8 str_idx, u8, u16 next_state_idx, u16 func_idx }
is
{ u16 str_idx, u16 next_state_idx, u16 func_idx }
No, they are getting str_idx as a byte. The next byte is just an alignment I guess (never used).
Edit: one quirk: if next_state_idx points to current state - this is an "execute w/o parameters" form (used for conflicts like "PREFIX:VALIDEXECCMD", "PREFIX:VALIDEXECCMD:CANHAVESUBCMD")
any idea what SYSTEM:OPTION? and DEBUG:REMOTE:OPTION= do?
SYSTEM:OPTION? should return a list of all active (not expired) options
DEBUG:REMOTE:OPTION? should return a list of all possible options with 0/1 flags appended to each one indicating the validity
DEBUG:REMOTE:OPTION= should accept an option list in the same format as DEBUG:REMOTE:OPTION?'s output and enable/disable many options in one shot (sounds cool
)
I think DEBUG:REMOTE:OPTION= should accept a license (or list of). Should be the same as entering the lic via the menu.
I don't see how it can accept a flag given that to activate you would need a license.
Usually the GET commands for options, let you specify the option for which you want to know the status.
I don't see how it can accept a flag given that to activate you would need a license.
The key check (MD5, XOR & friends) is performed at installation via menu only. It is NOT checked at each power on (only "byte0^byte1==byte2" check of that array at 0x903202BC).
s_remoteoption() handler parses a comma-separated list of shortened 2-letter option codes and single digit flags, then writes all flags to flash with a single call to sysFlashSet(buf, 4*18, 0x3202BC).
I was talking in logical terms.
But, this licensing really defies logic. Once again, well done @abyrvalg.
I just ran the SYSTEM:OPTION? and DEBUG:REMOTE:OPTION?
and here is what I got. Similar to what abyrvalg described
However, the list of options from DEBUG:REMOTE:OPTION?
does not completely make sense. First they only have two letters followed by a 0/1 indicating which one is supported I guess
but some of the two letter names do not correspond to any option it seems...and some options that we know of, dont seem to be in the list such as INM or AMA...
I didnt run the DEBUG:REMOTE:OPTION= because I was not still sure how it must be used/called.
can it be used to disable an option, too??
DEBUG:REMOTE:OPTION (both get and set) uses shortened names:
PA3 - PA
TG3 - TG
SO3 - SO
DMA - PM
AMA - DM
DFS - DF
KLS - DL
IBC - IB
IBF - IF
INM - SP
XDM - AD
BAS - SM
PAK - PK
SEM - SE
SPT - SB
PWM - MT
MKT - MK
U01 - U0
0/1 digit means "disabled/enabled". So yes, you can disable with this command too. Something like this:
DEBUG:REMOTE:OPTION PA1,TG1,SO0,SP0 - should enable PA3, TG3 and disable SO3, INM
DEBUG:REMOTE:OPTION (both get and set) uses shortened names:
PA3 - PA
TG3 - TG
SO3 - SO
DMA - PM
AMA - DM
DFS - DF
KLS - DL
IBC - IB
IBF - IF
INM - SP
XDM - AD
BAS - SM
PAK - PK
SEM - SE
SPT - SB
PWM - MT
MKT - MK
U01 - U0
0/1 digit means "disabled/enabled". So yes, you can disable with this command too. Something like this:
DEBUG:REMOTE:OPTION PA1,TG1,SO0,SP0 - should enable PA3, TG3 and disable SO3, INM
but I thought 0/1 only meant which options are supported on the unit and which ones are not allowed.
I'll give this a try later today