User Tools

Site Tools


pcb:preferences_subsystem

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
pcb:preferences_subsystem [2020/11/08 12:01]
cparker
pcb:preferences_subsystem [2021/02/28 19:56] (current)
cparker [Development Blog]
Line 7: Line 7:
   * The system should be able to interact with specified preferences files. \\ This allows subsystems to create their own if they want. It will also allow the user to specify such a file at startup.   * The system should be able to interact with specified preferences files. \\ This allows subsystems to create their own if they want. It will also allow the user to specify such a file at startup.
   * The system should manage the reading and writing of the files transparently. \\ We don’t want developers to have to think too hard about how this works.   * The system should manage the reading and writing of the files transparently. \\ We don’t want developers to have to think too hard about how this works.
-  * The system should not put constraints on what can be contained by the preference. \\ It should be allowed to be anything. Ultimately it’s a string when it’s stored and read, but it should be convertible into any data type. +  * The system should not put constraints on what can be contained by the preference. \\ It should be allowed to be anythingany data type.
-  * The files should be human readable. \\ There’s an interesting question here about locales…+
   * The system should be partitionable such that a subsystem may keep track of their own preferences without having to interact with the preferences of any other subsystem.   * The system should be partitionable such that a subsystem may keep track of their own preferences without having to interact with the preferences of any other subsystem.
 +
 +Specifically for the pcb system preferences...:​
 +  * The files should be human readable. \\ There’s an interesting question here about locales…
 +  * This should be able to handle the command line arguments as well.
 +  * I'd like to enforce that keys are unique, as this makes things easier. So, one subsystem shouldn'​t use the same key as another or the system.
 +
 +=== Architecture ===
 +The general problem is that we'd like to be able to store data, and then restore it to the software. The system should be able to handle any kind of data, and it should be able to accommodate different storage formats. A "​back-end"​ will be the part of the code that is responsible for storing data in a particular format. Each back-end should be familiar with a common set of data-types, including integers, floating points, and strings (bytes). More complex data-types will be stored as blocks of bytes, and it is expected that the implementor of the data-type will implement a converter function to do this. 
 +
 +The expectation is that subsystems are going to have their own structures to store their preferences,​ for example the Settings structure in global.h. So this system will generate descriptions of the preference data only. It will not actually retain the preference values, but rather read them and write them to the other locations in memory where the rest of the code expects to find them.
 +
 +That means that our work here is essentially going to be to define framework the describes the preference metadata so that we can save and load it in a programmatic fashion. To that end, we're going to define data structures that don't hold the preference data itself, but describe it and have a pointer to the actual data so that we can retrieve and store it. Preference metadata consists of things like name, help text, and data type. 
 +
 +There are a number of standard data types, including int, double, and string, and we'll also include a forth data type "​pointer"​ as essentially an "​other"​. This will allow the preference objects to be more complex structures.
 +
 +Ideally, we'll just be able to create a structure of metadata objects and say "save all of these to a file", or "load all of the data from that file according to these specs"​. To that end, we'll need a structure that we can iterate over. 
  
 === Process === === Process ===
Line 279: Line 294:
 == New Idea == == New Idea ==
  
 +===== Development Blog =====
 +I'm starting this because I'm having trouble remembering where I am and what I've done between development sessions.
 +
 +At this point, I've written data converters for ints, doubles, and strings. I've also written tests for them, so, I know they'​re working the way I think they should.
 +
 +== Tasks ==
 +  * Read function
 +
 += 20201108 =
 +
 +Today I managed to get a the function for writing preference files written, and a simple test that uses it.
 +
 +One note: when I initially wrote the test, I did something like this (abbreviated):​
 +<code c>
 +int intval;
 +char charvals[] = "​Preference string";​
 +PreferenceDefinition intpref = {.key = "​integer",​ .val = &​intval};​
 +PreferenceDefinition strpref = {.key = "​string",​ .val = &​charvals};​
 +</​code>​
 +However, this doesn'​t work. The val field of the strpref ended up equaling the address of charvals, whereas I needed it to be a double pointer. This makes me wonder what I ought to do here. If preferences are stored in a struct like
 +<code c>
 +typedef struct {
 +  char * charvals;
 +} Pref;
 +</​code>​
 +Then I have a pointer to point to. However, if the preferences are stored as "​global"​ variables, then I just get the address of the string, and I don't have a container to point to. I wonder if I need to have some sort of accommodation for that?
 +
 += 202201115 =
 +
 +I'm working today on the function that reads the files. I've looked at the current file format and it is pretty much "key = value"​. So, I think I'm going to allow that format also. That way I don't have to deal with trying to figure out how to get everyone'​s preferences converted to the new format. This means that I have to implement non-white-space delimiters, but I don't think that will be too hard. It also provides the developers with another option for delimiters. ​
 +
 += 20201227 = 
 +
 +Worked on the apply function. It works now. 
 +
 +I also found a bunch more functions related to attribute handling in hid/​common/​hidinit.[c,​h],​ and I'm starting to have a better sense of how the current systems work together. There'​s a "​node"​ list, and each subsystem registers a node that is effectively an array of HID_Attributes. There are functions for parsing the command line arguments, reading and writing files, etc, all similar in function to the code that I've just implemented...
 +
 +I need to think a little bit on how to handle these things hierarchically. How do subsystems inherit preferences from above? Can they back-propagate preferences?​ Can they share across-subsystems?​
 +
 +Thinking "​out-loud":​
 +When a subsystem wants to inherit something, it should be familiar with what it's parent'​s attributes are and just grab those attributes directly. It should only store locally things that are specific to the subsystem. ​
 +
 +But what if we passed a command-line parameter for a subsystem? The core won't know what to do with it because it's not in the core's list. We want that to be accessible to the subsystem, however. Maybe this is a good argument for the intermediate key/value pair structure. Perhaps we treat command-line arguments differently,​ and just save those vectors globally so that subsystems can inspect them at their leisure.
 +
 += 20210214 =
 +
 +In spite of keeping this blog for the purpose of remembering where I am... I've completely forgotten. I recall that I had started failing tests, and so I was rebuilding the system in a new branch to try to figure out where things went wrong. I guess I'm going to start getting back into this by bringing one class at a time into the new branch.
 +
 +Starting from master, I've added the PreferenceValue,​ PreferencePair,​ and preference cstring converters to the new base. This includes all of the tests, which pass.
 +
 +The next steps are to bring back in the apply functions, the parsing functions, and the file IO functions.
 +
 +One further note: support for PreferenceString isn't yet complete. There aren't converters for it, and it's not integrated with the reading and writing. The purpose of this data type is to allow arbitrary data to be stored in the files. Handling this type will require adding support for things like escape characters so that newlines and things can be included in the data. Right now I know that there'​s no arbitrary data that needs to be stored, so, I'm going to proceed without fully completing this, but, I probably need to add more remarks in the code about it.
 +
 += 20210228 = 
 +
 +As per usual, since I didn't have things completely laid out before-hand,​ I've made a bit of a mistake. I added a type enum to the PreferenceValue objects, however, these objects were supposed to point to the value in the preference structure, not actually contain the value themselves. It's probably still useful to have this type defined, but, not quite as useful as I had thought it would be.
 +
 +Now I've also created a PreferenceAlias type that is just a union of the different pref options. This will serve the purpose I had originally intended for PreferenceValue.
 +
 +The PreferenceDefinition type has been brought back into the fold, and all the tests now pass. This was a little tricky because I had to change a bunch of return values to PreferenceValue from char * in order to keep things more generic.
 +
 +All of the existing code has now been brought back into the codebase, and everything is passing its tests!
 +
 +Next steps are to figure out how to make this system handle command line arguments.
pcb/preferences_subsystem.1604854876.txt.gz · Last modified: 2020/11/08 12:01 by cparker