blob: 3cef58991484566acee5b61f226a0e4602e9995c [file] [log] [blame]
Josh Lehande745422020-11-07 02:14:09 -08001#pragma once
2
3#include "pid.hpp"
4
5#include <chrono>
6#include <cstring>
7#include <fstream>
8#include <iostream>
9#include <string>
10
11namespace pid_control
12{
13namespace ec
14{
15
16// Trivial class for information exported from core PID loop function
17struct PidCoreContext
18{
19 double input;
20 double setpoint;
21 double error;
22
23 double proportionalTerm;
24 double integralTerm1;
25 double integralTerm2;
26
27 double derivativeTerm;
28
29 double feedFwdTerm;
30 double output1;
31 double output2;
32
33 double minOut;
34 double maxOut;
35
36 double integralTerm3;
37 double output3;
38
39 double integralTerm;
40 double output;
41
42 bool operator!=(const PidCoreContext& rhs) const = default;
43 bool operator==(const PidCoreContext& rhs) const = default;
44};
45
46// Optional decorator class for each PID loop, to support logging
47// Although this is a trivial class, it ended up needing the Six Horsemen
48struct PidCoreLog
49{
50 std::string nameOriginal;
51 std::string nameClean;
52 std::ofstream fileContext;
53 std::ofstream fileCoeffs;
54 std::chrono::milliseconds lastLog;
55 PidCoreContext lastContext;
56 bool moved;
57
58 PidCoreLog() :
59 nameOriginal(), nameClean(), fileContext(), fileCoeffs(), lastLog(),
60 lastContext(), moved(false)
61 {}
62
63 PidCoreLog(const PidCoreLog& copy) = delete;
64
65 PidCoreLog& operator=(const PidCoreLog& copy) = delete;
66
67 PidCoreLog(PidCoreLog&& move)
68 {
69 // Reuse assignment operator below
70 *this = std::move(move);
71 }
72
73 PidCoreLog& operator=(PidCoreLog&& move)
74 {
75 if (this != &move)
76 {
Josh Lehan56ed7872022-12-15 00:15:28 -080077 // Move each field individually
78 nameOriginal = std::move(move.nameOriginal);
79 nameClean = std::move(move.nameClean);
80 fileContext = std::move(move.fileContext);
81 fileCoeffs = std::move(move.fileCoeffs);
82 lastLog = std::move(move.lastLog);
83 lastContext = std::move(move.lastContext);
Josh Lehande745422020-11-07 02:14:09 -080084
85 // Mark the moved object, so destructor knows it was moved
86 move.moved = true;
87 }
88 return *this;
89 }
90
91 ~PidCoreLog()
92 {
93 // Do not close files if ownership was moved to another object
94 if (!moved)
95 {
96 fileContext.close();
97 fileCoeffs.close();
98 }
99 }
100};
101
102// Initializes logging files, call once per PID loop initialization
103void LogInit(const std::string& name, pid_info_t* pidinfoptr);
104
105// Returns PidCoreLog pointer, or nullptr if this PID loop not being logged
106PidCoreLog* LogPeek(const std::string& name);
107
108// Logs a line of logging, if different, or it has been long enough
109void LogContext(PidCoreLog& pidLog, const std::chrono::milliseconds& msNow,
110 const PidCoreContext& coreLog);
111
112// Takes a timestamp, suitable for column 1 of logging file output
113std::chrono::milliseconds LogTimestamp(void);
114
115} // namespace ec
116} // namespace pid_control