Welcome to mirror list, hosted at ThFree Co, Russian Federation.

Event.cpp « Platform « src - github.com/Duet3D/RepRapFirmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 5439bed7c9547672bb3ba5839e2ebf63f91f81d2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
/*
 * Event.cpp
 *
 *  Created on: 18 Oct 2021
 *      Author: David
 */

#include <Platform/Platform.h>
#include <Platform/Event.h>
#include <RepRapFirmware.h>
#include <ObjectModel/ObjectModel.h>
#include <ObjectModel/Variable.h>

Event *_ecv_null Event::eventsPending = nullptr;
unsigned int Event::eventsQueued = 0;
unsigned int Event::eventsProcessed = 0;

// Private constructor, inline because it is only called from one place
inline Event::Event(Event *_ecv_null p_next, EventType et, uint16_t p_param, uint8_t devNum, CanAddress p_ba, const char *_ecv_array format, va_list vargs) noexcept
	: next(p_next), param(p_param), type(et), boardAddress(p_ba), deviceNumber(devNum), isBeingProcessed(false)
{
	text.vprintf(format, vargs);
}

// Queue an event, or release it if we have a similar event pending already. Returns true if the event was added, false if it was released.
/*static*/ bool Event::AddEvent(EventType et, uint16_t p_param, CanAddress p_ba, uint8_t devNum, const char *_ecv_array format, ...) noexcept
{
	va_list vargs;
	va_start(vargs, format);
	const bool ret = AddEventV(et, p_param, p_ba, devNum, format, vargs);
	va_end(vargs);
	return ret;
}

// Queue an event unless we have a similar event pending already. Returns true if the event was added.
// The event list is held in priority order, lowest numbered (highest priority) events first.
/*static*/ bool Event::AddEventV(EventType et, uint16_t p_param, uint8_t devNum, CanAddress p_ba, const char *_ecv_array format, va_list vargs) noexcept
{
	// Search for similar events already pending or being processed.
	// An event is 'similar' if it has the same type, device number, CAN address and parameter even if the text is different.
	TaskCriticalSectionLocker lock;

	Event** pe = &eventsPending;
	while (*pe != nullptr && (et >= (*pe)->type || (*pe)->isBeingProcessed))		// while the next event in the list has same or higher priority than the new one
	{
		if (et == (*pe)->type && devNum == (*pe)->deviceNumber &&(*pe)->param == p_param
#if SUPPORT_CAN_EXPANSION
			 && p_ba == (*pe)->boardAddress
#endif
		   )
		{
			return false;						// there is a similar event already in the queue
		}
		pe = &((*pe)->next);
	}

	// We didn't find a similar event, so add the new one
	*pe = new Event(*pe, et, p_param, p_ba, devNum, format, vargs);
	++eventsQueued;
	return true;
}

// Get the highest priority event and mark it as being serviced
/*static*/ bool Event::StartProcessing() noexcept
{
	TaskCriticalSectionLocker lock;

	Event * const ev = eventsPending;
	if (ev == nullptr)
	{
		return false;
	}
	ev->isBeingProcessed = true;
	return true;
}

// Get the name of the macro that we run when this event occurs
/*static*/ void Event::GetMacroFileName(const StringRef& fname) noexcept
{
	const Event * const ep = eventsPending;
	if (ep != nullptr && ep->isBeingProcessed)
	{
		fname.copy(ep->type.ToString());
		fname.cat(".g");
	}
}

// Get the macro parameters for the current event, excluding the S parameter which the caller will add
/*static*/ void Event::GetParameters(VariableSet& vars) noexcept
{
	const Event * const ep = eventsPending;
	if (ep != nullptr && ep->isBeingProcessed)
	{
		vars.InsertNewParameter("D", ExpressionValue((int32_t)(ep->deviceNumber)));
#if SUPPORT_CAN_EXPANSION
		vars.InsertNewParameter("B", ExpressionValue((int32_t)(ep->boardAddress)));
#endif
		vars.InsertNewParameter("P", ExpressionValue((int32_t)(ep->param)));
	}
}

// Get the default action for the current event
/*static*/ PrintPausedReason Event::GetDefaultPauseReason() noexcept
{
	const Event * const ep = eventsPending;
	if (ep != nullptr && ep->isBeingProcessed)
	{
		switch (ep->type.RawValue())
		{
		case EventType::heater_fault:
			return PrintPausedReason::heaterFault;

		case EventType::filament_error:
			return PrintPausedReason::filamentError;

		case EventType::driver_error:
			return PrintPausedReason::driverError;

		default:
			break;
		}
	}
	return PrintPausedReason::dontPause;
}

// Mark the highest priority event as completed
/*static*/ void Event::FinishedProcessing() noexcept
{
	TaskCriticalSectionLocker lock;

	const Event *ev = eventsPending;
	if (ev != nullptr && ev->isBeingProcessed)
	{
		eventsPending = ev->next;
		delete ev;
		++eventsProcessed;
	}
}

// Get a description of the current event
/*static*/ MessageType Event::GetTextDescription(const StringRef& str) noexcept
{
	const Event * const ep = eventsPending;
	if (ep != nullptr && ep->isBeingProcessed)
	{
		switch (ep->type.RawValue())
		{
		case EventType::heater_fault:
			{
				const char *_ecv_array heaterFaultText = HeaterFaultText[min<size_t>(ep->param, ARRAY_SIZE(HeaterFaultText) - 1)];
				str.printf("Heater %u fault: %s%s", ep->deviceNumber, heaterFaultText, ep->text.c_str());
			}
			return ErrorMessage;

		case EventType::filament_error:
			str.printf("Filament error on extruder %u: %s", ep->deviceNumber, FilamentSensorStatus(ep->param).ToString());
			return ErrorMessage;

		case EventType::driver_error:
#if SUPPORT_CAN_EXPANSION
			str.printf("Driver %u.%u error: %s", ep->boardAddress, ep->deviceNumber, ep->text.c_str());
#else
			str.printf("Driver %u error: %s", ep->deviceNumber, ep->text.c_str());
#endif
			return ErrorMessage;

		case EventType::driver_warning:
#if SUPPORT_CAN_EXPANSION
			str.printf("Driver %u.%u warning: %s", ep->boardAddress, ep->deviceNumber, ep->text.c_str());
#else
			str.printf("Driver %u warning: %s", ep->deviceNumber, ep->text.c_str());
#endif
			return WarningMessage;

		case EventType::driver_stall:
#if SUPPORT_CAN_EXPANSION
			str.printf("Driver %u.%u stall", ep->boardAddress, ep->deviceNumber);
#else
			str.printf("Driver %u stall", ep->deviceNumber);
#endif
			return WarningMessage;

		case EventType::main_board_power_fail:
			// This does not currently generate an event, so no text
			return ErrorMessage;

		case EventType::mcu_temperature_warning:
#if SUPPORT_CAN_EXPANSION
			str.printf("MCU temperature warning from board %u: temperature %.1fC", ep->boardAddress, (double)((float)ep->param/10));
#else
			str.printf("MCU temperature warning: temperature %.1fC", (double)((float)ep->param/10));
#endif
			return WarningMessage;
		}
	}
	str.copy("Internal error in Event");
	return ErrorMessage;
}

// Generate diagnostic data
/*static*/ void Event::Diagnostics(MessageType mt, Platform& p) noexcept
{
	p.MessageF(mt, "Events: %u queued, %u completed\n", eventsQueued, eventsProcessed);
}

// End