User Tools

Site Tools


t2:gpc_scripting:persistent_memory

GPC Persistent Memory

Persistent Memory allows you to store values to reuse them at a later time when powering on the T2 again and read settings of an Interactive Configuration.

The available functions:
Init: pmem_load
Read: pmem_read
Write: pmem_save pmem_write

ATTENTION: None of the pmem_ functions should be called on every interaction of main.

To use the pmem_ functions you need to know the Storage Size of the Data Types of your variables.
Not caring about their sizes will result in getting wrong values back when trying to read them from pmem again.

Introduction

Each slot of the Titan Two has 128 bytes (0..127) of PMEM storage available.
How many variables/data you can store into this space depends on the data types you want to store.

A bit is the smallest unit of storage. A bit stores just a 0 or 1.
1 bytes is a group of 8 bits (0..7). 2 bytes == 16 bits, 4bytes == 32 bits.

You can think of the PMEM storage like a table consisting of 128 rows with 8 columns.

Byte Offset Bit offsets
001234567
101234567
201234567
..01234567
12701234567

You can read and write this table only by byte_offset(rows) directly, not by bit_offset(columns).

Example:
The size of a variable of type fix32 is 4 bytes, 32bits : fix32 antirecoilX=13.5;
You can store it starting at any byte_offset.row you want, but because of its size it will write to the next 3 rows too. This limits the valid starting byte_offsets to 0..124, as writing it to 124 will write to 124,125,126,127 too.

A byte_offset.row can only be used by a single variable. The start byte_offset + the size of the data type can not overlap with the starting byte_offset.row of another one.
When storing a 4 byte size variable to byte_offset 0 (uses 0,1,2,3) the next available byte_offset.row is 4. To store a variable of type int16 (2 byte==16bits) you can't use 0,1,2,3 as its already in use, but you don't have to use 4, you can use any other starting byte_offset.row where all next 16bits are not already in use.

To store a boolean (0 or 1) you need 1 byte==8 bits. This sounds wrong at first. You have to remember we can write to the byte_offsets.rows only, not to a single bit_offset.
You can use a single variable to hold 8 bits(8bits==1byte) and write this variable to a byte_offset.row. The downside of this is you need a bit of code to handle this correctly.
If you have enough unused byte-offsets.rows available it is easier to just use one byte offset for one boolean (like an on/off toggle flag).

Usage Example

ATTENTION: None of the pmem_ functions should be called on every interaction of main.

To be able to access the persistent memory contents you have to use the function pmem_load first.
pmem_load() and pmem_read(…) should be called once at the init section of the script
and pmem_write(…) and pmem_save() only after a change of a values of a variable you want to update in pmem.

On pmem_read you prefix your variable with &
pmem_read(1,&yourvariable);
On pmem_write you do NOT use &
pmem_write(1,yourvariable);

Rapid Fire example with saving/loading speed adjustments and on/off toggle state

bool RapidFire;  // 1 byte == 8bits
uint16 RFPress;  // 2 bytes==16bits
uint16 RFRelease;// 2 bytes==16bits
 
init {
  pmem_load(); // this loads the memory correlated with the current memory slot
  pmem_read(0,&RapidFire); // rapid fire on/off state, byteoffset 0, 8bit (0)
  pmem_read(1,&RFPress);   // rapid fire press time, byteoffset 1, 16bit (1+2)
  pmem_read(3,&RFRelease); // rapid fire release time, byteoffset 3, 16bit (3+4)
 
  if (RFPress==0) RFPress=20;     // use maximum speed when no value
  if (RFRelease==0) RFRelease=20; // use maximum speed when no value
 
  // info output to GTuner IV Output Panel
  printf("Rapid Fire state (1=On,0=Off) : %d , Press Time: %d, Release Time: %d"
                                                 ,RapidFire,RFPress,RFRelease);
}
 
main {
   // hold L2/LT & press DPad_UP to toggle rapid fire
   if (get_actual(BUTTON_8) && event_active(BUTTON_10)) {
       RapidFire=!RapidFire;                        // invert current state
       printf("Rapid Fire is now: %d",RapidFire); 
       pmem_write(0,RapidFire); // write to pmem, is not saved yet
       pmem_save();             // save it now
   }
 
   // hold L2/LT & press DPad_Left to increase speed / decrease wait & press time
   if (get_actual(BUTTON_8) && event_active(BUTTON_12)) {
       RFRelease=RFPress=clamp(RFPress -=10,20,1000); // limit values to 20..1000
       printf("Rapid Speed is now: %d | %d",RFPress,RFRelease); 
       pmem_write(1,RFPress);   // write to pmem, is not saved yet
       pmem_write(3,RFRelease); // write to pmem, is not saved yet
       pmem_save();             // save it now
   }
 
   // hold L2/LZ & press DPad_Right to decrease speed/increase wait&press time
   if (get_actual(BUTTON_8) && event_active(BUTTON_13)) {
       RFRelease=RFPress=clamp(RFPress +=10,20,1000); // limit values to 20..1000
       printf("Rapid Speed is now: %d | %d",RFPress,RFRelease);
       pmem_write(1,RFPress);    // write to pmem, is not saved yet
       pmem_write(3,RFRelease); // write to pmem, is not saved yet
       pmem_save();             // save it now
   }
   // when enabled and fire button is active run rapid fire combo
   if (RapidFire && get_actual(BUTTON_5)) combo_run(cRapidFire);
}
 
combo cRapidFire {
   set_val(BUTTON_5,100); wait(RFPress); // press button
   set_val(BUTTON_5,0); wait(RFRelease); // release button
}
t2/gpc_scripting/persistent_memory.txt · Last modified: 2019/01/22 03:33 by scachi