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
|
/*
* GCodes7.cpp
*
* Created on: 14 Sept 2022
* Author: David
*
* This file handles M291, M292 and other functions related to message boxes
*/
#include "GCodes.h"
#include "GCodeBuffer/GCodeBuffer.h"
// Process M291
GCodeResult GCodes::DoMessageBox(GCodeBuffer&gb, const StringRef& reply) THROWS(GCodeException)
{
// Get the message
gb.MustSee('P');
String<MaxMessageLength> message;
gb.GetQuotedString(message.GetRef());
// Get the optional message box title
bool dummy = false;
String<StringLength100> title;
(void)gb.TryGetQuotedString('R', title.GetRef(), dummy);
// Get the message box mode
uint32_t sParam = 1;
(void)gb.TryGetLimitedUIValue('S', sParam, dummy, 8);
// Get the optional timeout parameter. The default value depends on the mode (S parameter).
float tParam = (sParam <= 1) ? DefaultMessageTimeout : 0.0;
gb.TryGetNonNegativeFValue('T', tParam, dummy);
MessageBoxLimits limits;
gb.TryGetBValue('J', limits.canCancel, dummy);
AxesBitmap axisControls;
switch (sParam)
{
case 0: // no buttons displayed, non-blocking
if (tParam <= 0.0)
{
reply.copy("Attempt to create a message box that cannot be dismissed");
return GCodeResult::error;
}
break;
case 1: // Close button displayed, non-blocking
default:
break;
case 2: // OK button displayed, blocking
case 3: // OK and Cancel buttons displayed, blocking
// Message box modes 2 and 3 can take a list of axes that can be jogged
for (size_t axis = 0; axis < numTotalAxes; axis++)
{
if (gb.Seen(axisLetters[axis]) && gb.GetIValue() > 0)
{
axisControls.SetBit(axis);
}
}
break;
case 4: // Multiple choices, blocking
gb.MustSee('K');
limits.choices = gb.GetExpression();
if (limits.choices.IsHeapStringArrayType())
{
uint32_t defaultChoice = 0;
if (gb.TryGetUIValue('F', defaultChoice, dummy))
{
limits.defaultVal.SetInt((int32_t)defaultChoice);
}
break;
}
reply.copy("K parameter must be an array of strings");
return GCodeResult::error;
case 5: // Integer value required, blocking
limits.GetIntegerLimits(gb, false);
break;
case 6: // Floating point value required, blocking
limits.GetFloatLimits(gb);
break;
case 7: // String value required, blocking
limits.GetIntegerLimits(gb, true);
break;
}
if (sParam >= 2) // if it's a blocking message box
{
// Don't lock the movement system, because if we do then only the channel that issues the M291 can move the axes
#if HAS_SBC_INTERFACE
if (reprap.UsingSbcInterface())
{
gb.SetState(GCodeState::waitingForAcknowledgement);
}
#endif
if (Push(gb, true)) // stack the machine state including the file position
{
UnlockMovement(gb); // allow movement so that e.g. an SD card print can call M291 and then DWC or PanelDue can be used to jog axes
gb.WaitForAcknowledgement(); // flag that we are waiting for acknowledgement
}
}
// Display the message box on all relevant devices. Acknowledging any one of them clears them all.
const MessageType mt = GetMessageBoxDevice(gb); // get the display device
reprap.SendAlert(mt, message.c_str(), title.c_str(), (int)sParam, tParam, axisControls, &limits);
return GCodeResult::ok;
}
// Process M292
GCodeResult GCodes::AcknowledgeMessage(GCodeBuffer&gb, const StringRef& reply) THROWS(GCodeException)
{
uint32_t seq = 0;
if (gb.Seen('S'))
{
seq = gb.GetUIValue();
}
bool wasBlocking;
if (reprap.AcknowledgeMessageBox(seq, wasBlocking))
{
if (wasBlocking)
{
const bool cancelled = (gb.Seen('P') && gb.GetIValue() == 1);
ExpressionValue rslt;
if (!cancelled && gb.Seen('R'))
{
rslt = gb.GetExpression();
}
MessageBoxClosed(cancelled, true, rslt);
}
return GCodeResult::ok;
}
else
{
reply.copy("no active message box");
return GCodeResult::error;
}
}
// Deal with processing a M292 or timing out a message box
void GCodes::MessageBoxClosed(bool cancelled, bool m292, ExpressionValue rslt) noexcept
{
platform.MessageF(MessageType::LogInfo,
"%s: cancelled=%s",
(m292) ? "M292" : "Message box timed out",
(cancelled ? "true" : "false"));
for (GCodeBuffer* targetGb : gcodeSources)
{
if (targetGb != nullptr)
{
targetGb->MessageAcknowledged(cancelled, rslt);
}
}
}
// End
|