-
Notifications
You must be signed in to change notification settings - Fork 0
Methods
Producer functions make calls to functions from other headers (typically libc, libstd++, dlfcn.h, etc.) to get relevant system, user and hardware information. After retrieving this information, these functions format and store the data in a given cylonStruct.
-
void produceUserProfile(struct cylonStruct& tf)
-
This function sets the pictureLocation field to a default value since this field is not used for the Linux side of the Final Five Project. It then retrieves the uid and passwd using traditional getters. If the passwd struct is not null, the username is extracted and stored in the username field of the given cylonStruct. A string is then created using the username field and a constant AVATAR_PATH value (the traditional path to a user's profile icon image in most Linux distros). This path is then passed into an ifstream object, if the file is found to exist, the picturePath is set to the value of the string that was tested, and the pictureType field is set to the constant value of AVATAR_TYPE (which by default is ".png" but can be modified for your system if it stores user profile images as, say, ".jpg" instead). If the file does not exist, the picturePath & pictureType fields are set to default values. Finally, the ifstream object is closed. In instances where the passwd struct is found to be NULL, the username, picturePath and pictureType fields are all set to default values.
-
void produceDateTimeZone(struct cylonStruct& et)
-
This function creates a new time_t object using the std::time() call. The value is then converted to a tm pointer via the localtime() method. The milliseconds field of the given cylonStruct is set to a default value for the Linux version of the Final Five project as it is unavailable as its own field in the time header used in the LSB. The seconds, minutes, day, date, month, year, dst, timeZoneName, and timeZone fields are all then either copied directly or slightly modified from the fields in the tm pointer and stored in the given cylonStruct. To match the mapping used by other Final Five Project libraries, the month is incremented by 1 and the year is incremented by 1900.
-
void produceDeviceName(struct cylonStruct& et)
-
This function makes a call to gethostname(), and if the result is found to be non-zero, just sets the given cylonStruct's deviceName field to a default value and returns early. Otherwise, the char buffer used in the gethostname() call is converted to a string and stored in the deviceName field of the cylonStruct.
-
void produceProcessorInfo(struct cylonStruct& et)
-
This function sets the processorCount field equal to that of the result of sysconf(_SC_NPROCESSORS_ONLN). A FILE pointer is then opened on the "/proc/cpuinfo" object and read into a buffer before being closed. If the result of the fread() call is 0 or greater than the size of the buffer itself, a default value is used for the given cylonStruct's hertz, processorLevel and architecture fields. Otherwise, the buffer is null terminated and a char pointer is used with string stream to search the buffer for specific lines in the buffer that contain the values we wish to extract from the buffer and store in the given cylonStruct. If the char* turns out to be null, a default value is used for the associated field. Otherwise, sscanf() is called and the appropriate value is extracted from the correct line and stored in the related field of the cylonStruct. For the hertz field, since cpuinfo stores clock speed in MHz, the value is first converted to Hz to match the mapping used by the Final Five Project. To retrieve the architecture field, an utsname struct is populated using the uname() call. If the result of this call is non-zero, a default value is used. Otherwise, the machine field of the utsname struct is copied into the architecture field of the given cylonStruct.
-
void produceMemoryInfo(struct cylonStruct& et)
-
This function populates a sysinfo struct with the sysinfo() call. The memoryBytes and bytesAvails fields are then copied from the totalram and freeram fields respectively. The threshold field of the given cylonStruct is set to the totalram field multiplied by the lowMemory float established at the start of the method. pageSize and allocationGranularity, being the same concept in Linux-based systems, are both set equal to the result of sysconf(_SC_PAGESIZE). The minAppAddress and maxAppAddress fields are unused in the Linux version of the Final Five Project and are net to default values. The lowMemory field of the given cylonStruct is calculated based on the ratio of freeram/totalram in relation to the lowMemory float established at the start of the method. The osArchitecture field of the given cylonStruct are set equal to the value of __WORDSIZE if it is a multiple of two, otherwise it is set to a default value.
-
void produceDeviceInformation(struct cylonStruct& et)
-
Calls all other produceDeviceX methods in one collected spot. Finally sets the detectedDeviceCount to the size of the given cylonStruct's detectedDevice's list.
-
void produceControllerInfo(struct cylonStruct& et)
-
This method starts by checking if libsdl was loaded into the main dynamically linked libs table. If not, it returns w/o executing. An attempt is then made to load the mappings from the included SDL_GameControllerDB text file (on failure, a warning is noted, but the code proceeds). Having verified that libsdl is properly loaded, several symbols are cast from the function addresses provided by the lib from loadLibs() to make calls to the SDL library. Upon casting these symbols, the count of all attached SDL_Joysticks is recorded, if the number is less than 1, the method returns, otherwise it proceeds. A for loop then iterates over this joystick count and creates an SDL_Joystick pointer for each joystick index, if a failure to open the joystick device occurs that device is skipped and the loop is forced to the next iteration. If the Joystick is found to also be an SDL_GameController device, the process is repeated for opening an SDL_GameController pointer, and continuing to another device on failure. If the gameController was successfully opened, a deviceStruct and controllerStruct are built using the appropriate methods. A quick check is done to verify that the player number of the devices is non-negative, if the check fails an error flag is set in the provided cylonStruct for INVALID_CONTROLLER_ID. The controllerStruct's axis values are captured and normalized to the value ranges utilized by Centurion. Finally, the gameController-based controllerStruct and deviceStruct are pushed into the back of the devices and controllers fields for the provided cylonStruct, and the lists are synchronized for mapping the two structures together.
In cases where the device is found to NOT be an SDL_GameController, the process of structure creation, player number checking, list pushing/synchronizing is all repeated. The only omission is the capture of the values of the axis on the joystick-based device. -
void produceUsbDeviceInfo(cylonStruct& et)
-
This method immediately returns if it finds that libusb was not set to opened in the allLibs table for Ellen.cpp. If libusb was successfully opened prior to calling this method, it continues by initing libusb's functionality. If the initialization call fails, the method immediately returns. Otherwise, a list of usb devices is retrieved (again, if a failure occurs, the method returns immediately). If no failure occurs, the list is iterated over, and device descriptors are retrieved for each libusb_device object in the list. If the library is unable to retrieve a descriptor for a given USB device, a dummy device is created and stored in the temporary deviceStruct list created at the start of the method. The process is then repeated to grab the active config descriptor for each device, on failure a USB-based deviceStruct is still created and stored in the temporary list created at the start of the method. If no failures have occurred, the interface class is ripped from the interface descriptor and used to build a more fleshed out USB-based deviceStruct, which is then stored in the temporary USB devices list (created at the start of the method). The libusb_device array that was being iterated over then has its memory freed and libusb_exit is called. A FILE pointer is then opened to pipe in a console response for the "lsusb" command. If the pipe is null, it is closed and the method exits. Otherwise, the pipe results are read into a buffer, and the pipe is closed. If the result is a non-positive number of bytes read into the buffer, the method will also return. The buffer is then parsed into a vector of std::string type, and utilizing stringstreams and sscanf() the name, and udev device number are gleaned from the strings and stored in the appropriate deviceStruct. The deviceStruct is then removed from the temporary list created for this method and stored in the given cylonStruct's detectedDevice's list at the back of the list. This process is repeated for all devices in the temporary list until it is empty.
-
void produceDisplayInfo(struct cylonStruct& et)
-
This method returns immediately if libsdl in ellen.cpp's allLibs table is not found to be opened. The SDL library is used to retrieve the total number of detected display devices attached to the current machine, if this number is non-positive the method returns early. A for-loop is then run over the length of the display count, and a displayStruct and deviceStruct are created based on the name and index of each attached display, before being placed into the synchronized detectedDevices and displayDevices lists for the given cylonStruct.
-
void produceStorageInfo(struct cylonStruct& et)
-
This method returns immediately if the given cylonStruct has an empty username field (as, at least for distros similar to Ubuntu as of this writing, the username is required to form the path to some storage locations retrieved). A path string is created using the username field of the given cyclonStruct, and an opendir call is attempted on this path. If successful, the files inside the media path are inspected one at a time. If these are not the files "." or "..", they are considered a storage drive. Each file is also inspected to verify if it meets the DT_DIR filetype defined in dirent.h. For all devices that meet both of these requirements, a new path string is built using the directory's name and statvfs() is called on that path. If successful, the total space and free space for that directory are calculated and saved, and then used along with the path string for the directory to form a new deviceStruct and storageStruct. These structures are then put into the back of the given cylonStruct's detectedDevices and storages lists respectively, and the lists are synchronized. Finally, the media path is closed using closedir before moving on to part 2.
-
Part 2 of this method tries to create a storage/device structure based on the user's home directory on the main hard drive the OS is running on. A new path string is created using the username field of the given cylonStruct and an opendir() call is attempted. If successful, statvfs() is called on the path, and if that is also successful the free/total space in bytes is calculate for the user's home directory and used with the path string to create a storageStruct and deviceStruct which are stored in the appropriate lists for the given cylonStruct, which then synchronizes these lists for mapping the devices between the two. Finally, the home path is closed using closdir before moving on to part 3.
-
Part 3 of this method tries to create storageStructs based on any attached MTP USB devices using GVFS. getuid() is called to get the user's effective ID, and an ostringstream is used to build a new path string. If opendir() is successful on this path, all files inside are inspected. If the file is found to match the pattern associated with MTP USB devices, a flag is set for this file. statvfs() is then called on the given file, and if successful the free/total space are calculated. If these numbers are non-negative and the total space is at least as big as the free space and the USB MTP flag is set for a given file, sscanf() is used to glean the name, usb port and udev device number from the path. These values are then used to match the USB MTP device to a pre-existing USB deviceStruct in the given cylonStruct's detectedDevice's list. If a match is found while iterating through the detectedDevice's list, a new storageStruct is built, placed in the cylonStruct's storages list and the lists are synchronized to map between the two structures, this will cause the iterator to break early to prevent anymore unnecessary iteration through any remaining devices. If no match is found, a new deviceStruct and storageStruct are created, stored in the appropriate lists of the cylonStruct, and mapped together.
-
Part 4 of this method handles all remaining files found in the GVFS mounting path for the current user that did not meet the MTP/USB matching patterns. If the file is not "." or "..", new storage and device structures are created, stored in the appropriate lists of the cylonStruct, and mapped together using their path names and the detected free space/total space (which is also verified to be positive and of a ratio between 0 and 1 in terms of free space/total space). Finally the directory opened in part 3 is closed using closedir.
-
void produceLog(struct cylonStruct& et)
-
Prints out a quick log containing the cylonStruct's location in memory, as well as the values of all other fields.
Builder functions are similar to constructors. They call various producers to create an object, and then return the fully formed structure for consumption by another method.
-
struct cylonStruct buildEllen()
-
This function acts similar to a constructor for a cylonStruct. The struct is initialized and then filled by many of the above producer methods, finally returning the new cylonStruct.
-
struct deviceStruct buildBlankDevice()
-
Creates a dummy device with default/error values for all fields.
-
struct buildUsbDevice(struct libusb_device usbDev, struct libusb_device_descriptor descriptor)*
-
Returns a dummy device if libusb is found to not be opened in the allLibs table for ellen.cpp. Otherwise, builds and returns a deviceStruct based off of data from the libusb structures.
-
struct deviceStruct buildUsbDevice(struct libusb_device usbDev, struct libusb_device_descriptor descriptor, int interfaceClass)*
-
Returns a dummy device if libusb is found to not be opened in the allLibs table for ellen.cpp. Otherwise, builds and returns a deviceStruct based off of data from the provided libusb structures. Used for devices whose class is defined in their interface for libusb.
-
struct deviceStruct buildControllerDevice(int index, const char deviceName, int instanceID)*
-
Returns a deviceStruct to be paired with a corresponding controllerStruct based on the fields provided.
-
struct deviceStruct buildDisplayDevice(const char displayName, int i)*
-
Returns a deviceStruct based off of data provided to be paired with a corresponding displayStruct.
-
struct deviceStruct buildStorageDevice(std::string storageName)
-
Returns a deviceStruct meant to be paired with a storageStruct used to represent some sort of storage drive, partition, or external storage device.
-
struct controllerStruct buildBlankController()
-
Returns a dummy controllerStruct whose fields are only populated with default/error values.
-
struct controllerStruct buildController(deviceStruct device, int index, int id)
-
Returns a controllerStruct paired with the given deviceStruct argument based on the player number and unique ID fields provided.
-
struct displayStruct buildBlankDisplay()
-
Returns a dummy displayStruct whose fields are only populated with default/error values.
-
struct displayStruct buildDisplay(struct deviceStruct device, int i)
-
Returns a displayStruct paired with the given deviceStruct argument based on the display number field provided. Will return a dummy displayStruct in cases where libsdl is found to not be opened in the allLibs table for ellen.cpp. The builder makes a call to get the display bounds and display mode of the display at the provided display number argument, and stores this information in the struct to be returned.
-
struct storageStruct buildStorage(struct deviceStruct device, std::string path, uint64_t freeSpace, uint64_t totalSpace)
-
Returns a storageStruct based on the provided data and paired with the provided deviceStruct argument.
Controller functions are used for handling various aspects of controllerStruct device input.
-
void pollControllerEvents(struct cylonStruct& et)
-
If libsdl is found to not be opened in the allLibs table, this method returns immediately. Otherwise, so long as there are SDL_Events to be run, that event is pulled out and interpreted through a large chain of if-logic, with different behaviors depending on what the type of the event was
-
If the event is of type SDL_CONTROLLERBUTTONDOWN, the method verifies that the button tied to the event is still in a pressed state and iterates through the provided cylonStruct's controllers list to find the offending controllerStruct, then polls the status of the controller to update its buttons mask
-
If the event is of type SDL_CONTROLLERBUTTONUP, the method iterates through the provided cylonStruct's controllers list to find the offending controllerStruct, then polls the status of the controller to update its buttons mask
-
If the event is of type SDL_CONTROLLERAXISMOTION, the method iterates through the provided cylonStruct's controllers list to find the offending controllerStruct, then verifies which axis triggered the event, normalizes the value and updates the axis value for the found controllerStruct
-
If the event is of type SDL_CONTROLLERDEVICEADDED, the method attempts to open an SDL_GameController and SDL_Joystick pointer for the device that caused the event to trigger. The list of controllers for the given cylonStruct is then iterated through if opening both of these objects was successful. If the ID's are found to match to a pre-existing device, a flag is set denoting that the device is an existing instance. If at the end of the iteration the flag is still set to false, a new deviceStruct and controllerStruct are created. The axes for the controller are set, then both devices are pushed into the back of their appropriate lists in the provided cylonStruct, and then the two structs are mapped together and the controllers/devices lists are resynchronized.
-
If the event is of type SDL_CONTROLLERDEVICEREMOVED, the method iterates over the controllers list of the provided cylonStruct. If the ID of a node in the list matches that of the device that triggered event, the detectedDevices list is also iterated through and the matching deviceStruct is erased from the detectedDevices list, causing the inner iteration to break. The offending controllerStruct is then also erased, and the lists are finally synchronized.
-
If the event is of type SDL_JOYBUTTONDOWN, the method verifies that the button state is still pressed, then iterates through the given cylonStruct's controllers list. If a controllerStruct is found with a matching ID that also is NOT an SDL_GameController device, the buttons mask for that controllerStruct is updated. If the device is a Playstation style device, some additional axis modification will be done for the triggers since SDL_Joystick PSX controllers treated their triggers as buttons in testing.
-
If the event is of type SDL_JOYBUTTONUP, the method verifies that the button state is still released, then iterates through the given cylonStruct's controllers list. If a controllerStruct is found with a matching ID that also is NOT an SDL_GameController device, the buttons mask for the controllerStruct is udpated. If the device is a Playstation style device, some additional axis modification will be done for the triggers since SDL_Joysticvk PSX controllers treated their triggers as buttons in testing.
-
If the event is of type SDL_JOYAXISMOTION, this method iterates through the controllers list of the provided cylonStruct. If a matching controllerStruct is found that is also NOT an SDL_GameController device, the axes values are normalized and updated for the controllerStruct depending on which axis caused the event to be fired and what style of controller was being used (Playstation style vs Xbox, etc. style). Additional math is done for the triggers of Xbox style devices since SDL_Joystick devices use a different range for their triggers than SDL_GameControllers.
-
If the event is of type SDL_JOYHATMTION, the method iterates through the controllers list of the provided cylonStruct. If a matching controllerStruct is found that is also NOT an SDL_GameController device, the buttons mask for the offending device is updated to match the D-Pad input logged in the event.
-
If the event is of type SDL_JOYDEVICEADDED, the method will return immediately if the offending device is an SDL_GameController. If an SDL_Joystick pointer can be successfully opened from the which field of the event's jdevice struct, the list of controllers for the provided cylonStruct is iterated over and a flag is set if any matching controllerStructs are detected. If a match is detected, a new deviceStruct and controllerStruct are created, the axes are normalized and stored for the controllerStruct, and both structs are placed in the appropriate cylonStruct lists. Finally, the two lists are resynchronized.
-
If the event is of type SDL_JOYDEVICEREMOVED, the method will iterate over the controllers list of the provided cylonStruct. If a matching controllerStruct is found, the detectedDevices list is also iterated over to find the node in that list matching the superDevice field of the controllerStruct that triggered the event. The matching deviceStruct is erased from the list, and the inner iteration is broken. The offending controllerStruct is also erased, again breaking the outer iteration. Finally, both lists are resynchronized so the mappings of any remaining devices remain intact.
-
uint16_t pollButtons(uint16_t buttons, SDL_Event event, bool isGameController)
-
This method returns immediately if libsdl is found to not have been opened in the allLibs table for ellen.cpp. The button and state values used within the method are populated based on whether the isGameController flag is set to true (so the fields rip from the cbutton struct of the event argument) or false (the fields rip from the jbutton struct of the event argument). The state variable is then inspected through a large if-else chain to determine which button was pressed, and to set/erase the corresponding but in the buttons bit mask variable. If a button's state is said to be pressed, the corresponding bit in the mask is made hot. If the button is said to be released AND the buttons mask already shows that the bit for that button is already set, the bit is erased in the buttons mask. The method ends by returning the updated buttons mask.
-
float normalizeAxis(float oldAxisValue, bool isTrigger)
-
This method normalizes a given SDL axis value to use the axis ranges from Cylon.h (-1.0 to 1.0 for sticks and 0.0 to 1.0 for triggers) and returns the normalized value as a float object.
-
bool isPSX(std::string gamepadName)
-
This method is a quick "hack" check to determine if a given name contains any mention of Playstation branding. If a key phrase is detected, the method returns true, otherwise it returns false.
-
*void synchControllerDevices(struct cylonStruct et)
-
This method returns immediately if libsdl is found to not be opened in the allLibs table in ellen.cpp. Otherwise, an attempt is made to retrieve the number of joystick devices detected by SDL. If the value is non-positive, an error bit is set in the provided cylonStruct's error field. A for loop is then run over the length of that retrieved count, and an attempt is made to open an SDL_Joystick pointer for each round in the loop. If an SDL_Joystick cannot be opened on a given index, an error bit is set in the cylonStruct's error field. Otherwise, an attempt is made to retrieve the instance ID of this SDL_Joystick. If this attempt fails, an additional error bit is set in the error field of the cylonStruct and the method returns. Otherwise, the method then iterates over the controllers list of the given cylonStruct, and a counter is established to keep track of how many devices into the list the iterator is at a given round in the loop. If the retrieved instance ID matches the ID of a controllerStruct in the controllers list, the userIndex and superDevice.controllerIndex fields are updated to the appropriate values. An inner iteration for all deviceStructs in detectedDevices also occurs for each controllerStruct in controllers, and if the id's of the two iterators match and the device iterator's device type is found to be CONTROLLER_TYPE, the controllersIndex field for the device iterator deviceStruct is also updated, completing the mapping between the two lists.
-
void sdlInit()
-
This method exits immediately if libsdl is found to not be opened in the allLibs table in ellen.cpp. Otherwise, a hint is set to allow listening for background events (this allows controller input to be listened for even when the window is not visible). An attempt is then made to call SDL_Init with the SDL_INIT_EVERYTHING flag. If this fails, the method prints a warning, closes the dynamically linked libraries, and returns. An attempt is then made to set a doublebuffer via SDL_GL_SetAttribute. This call is optional and is just used for our personal demo app rendering that we plugged Ellen into. For more information please see SDL2's documentation. Finally, an attempt is made to create a hidden SDL_Window, printing a message if a failure occurs.
Linking functions are used for dynamically loading in libraries that may or may not be available on a given version of Linux.
-
void fillTable()
-
This function fills the dynLib structure array "allLibs" with information on a given library at a set index.
-
void openLibs()
-
This function attempts to open a library file via the dlopen() call, counting down in version number until the latest version installed is located. If the dlopen() call is successful, the address for the library is stored in the proper location in allLibs, and the functions array of that lib's index in allLibs is populated utilizing a for loop that runs of the library's functionCount field and the dlsym() method.
-
void closeLibs()
-
This function runs over the entirety of the allLibs structure and attempts to close the libraries found to be opened using dlclose().