@@ -877,22 +877,12 @@ GCodeResult Heat::ConfigureSensor(GCodeBuffer& gb, const StringRef& reply)
877877 }
878878
879879#if SUPPORT_CAN_EXPANSION
880- // Set boardAddress to the board number that the port is on, or NoCanAddress if the port was not given
880+ // Set boardAddress to the board number that the port is on, or MasterAddress if the port was not given
881881 CanAddress boardAddress;
882882 String<StringLength20> portName;
883- if (gb.Seen (' P' ))
884- {
885- if (!gb.GetReducedString (portName.GetRef ()))
886- {
887- reply.copy (" Missing port name" );
888- return GCodeResult::error;
889- }
890- boardAddress = IoPort::RemoveBoardAddress (portName.GetRef ());
891- }
892- else
893- {
894- boardAddress = CanId::NoAddress;
895- }
883+ boardAddress = (gb.Seen (' P' ) && gb.GetReducedString (portName.GetRef ()))
884+ ? IoPort::RemoveBoardAddress (portName.GetRef ())
885+ : CanId::MasterAddress;
896886#endif
897887 bool newSensor = gb.Seen (' Y' );
898888 if (newSensor)
@@ -909,11 +899,6 @@ GCodeResult Heat::ConfigureSensor(GCodeBuffer& gb, const StringRef& reply)
909899 }
910900
911901#if SUPPORT_CAN_EXPANSION
912- if (boardAddress == CanId::NoAddress)
913- {
914- reply.copy (" Missing port name" );
915- return GCodeResult::error;
916- }
917902 TemperatureSensor * const newSensor = TemperatureSensor::Create (sensorNum, boardAddress, typeName.c_str (), reply);
918903#else
919904 TemperatureSensor * const newSensor = TemperatureSensor::Create (sensorNum, typeName.c_str (), reply);
@@ -968,31 +953,144 @@ const char *Heat::GetHeaterSensorName(size_t heater) const
968953 return (h.IsNotNull ()) ? h->GetSensorName () : nullptr ;
969954}
970955
971- // Return the protection parameters of the given index
972- HeaterProtection& Heat::AccessHeaterProtection ( size_t index) const
956+ // Configure heater protection (M143). Returns true if an error occurred
957+ GCodeResult Heat::SetHeaterProtection (GCodeBuffer& gb, const StringRef& reply)
973958{
974- if (index >= FirstExtraHeaterProtection && index < FirstExtraHeaterProtection + NumExtraHeaterProtections)
959+ WriteLocker lock (heatersLock);
960+
961+ bool seen = false ;
962+ int32_t heaterNumber = 1 ; // default to extruder 1 if no heater number provided
963+ gb.TryGetIValue (' H' , heaterNumber, seen);
964+ const int index = (gb.Seen (' P' )) ? gb.GetIValue () : heaterNumber;
965+
966+ if ( index < 0
967+ || (index >= (int )MaxHeaters && index < (int )FirstExtraHeaterProtection)
968+ || index >= (int )(FirstExtraHeaterProtection + NumExtraHeaterProtections)
969+ )
970+ {
971+ reply.printf (" Invalid heater protection item '%d'" , index);
972+ return GCodeResult::error;
973+ }
974+
975+ HeaterProtection &item = (index >= (int )FirstExtraHeaterProtection)
976+ ? *heaterProtections[index - FirstExtraHeaterProtection + MaxHeaters]
977+ : *heaterProtections[index];
978+ // Set heater to control
979+ if (seen && heaterNumber != item.GetHeater ())
980+ {
981+ const int oldHeaterNumber = item.GetHeater ();
982+ item.SetHeater (heaterNumber);
983+ UpdateHeaterProtection (oldHeaterNumber);
984+ UpdateHeaterProtection (heaterNumber);
985+ }
986+
987+ // Set sensor that supervises the heater
988+ if (gb.Seen (' X' ))
975989 {
976- return *heaterProtections[index + MaxHeaters - FirstExtraHeaterProtection];
990+ item.SetSensorNumber (gb.GetIValue ());
991+ seen = true ;
992+ }
993+
994+ // Set trigger action
995+ if (gb.Seen (' A' ))
996+ {
997+ const int action = gb.GetIValue ();
998+ if (action < 0 || action > (int )MaxHeaterProtectionAction)
999+ {
1000+ reply.printf (" Invalid heater protection action '%d'" , action);
1001+ }
1002+
1003+ seen = true ;
1004+ item.SetAction (static_cast <HeaterProtectionAction>(action));
9771005 }
978- return *heaterProtections[index];
1006+
1007+ // Set trigger condition
1008+ if (gb.Seen (' C' ))
1009+ {
1010+ const int trigger = gb.GetIValue ();
1011+ if (trigger < 0 || trigger > (int )MaxHeaterProtectionTrigger)
1012+ {
1013+ reply.printf (" Invalid heater protection trigger '%d'" , trigger);
1014+ }
1015+
1016+ seen = true ;
1017+ item.SetTrigger (static_cast <HeaterProtectionTrigger>(trigger));
1018+ }
1019+
1020+ // Set temperature limit
1021+ if (gb.Seen (' S' ))
1022+ {
1023+ const float limit = gb.GetFValue ();
1024+ if (limit <= BadLowTemperature || limit >= BadErrorTemperature)
1025+ {
1026+ reply.copy (" Invalid temperature limit" );
1027+ return GCodeResult::error;
1028+ }
1029+
1030+ seen = true ;
1031+ item.SetTemperatureLimit (limit);
1032+ }
1033+
1034+ // Report current parameters
1035+ if (!seen)
1036+ {
1037+ if (item.GetHeater () < 0 )
1038+ {
1039+ reply.printf (" Temperature protection item %d is not configured" , index);
1040+ }
1041+ else
1042+ {
1043+ const char *actionString, *triggerString;
1044+ switch (item.GetAction ())
1045+ {
1046+ case HeaterProtectionAction::GenerateFault:
1047+ actionString = " generate a heater fault" ;
1048+ break ;
1049+ case HeaterProtectionAction::PermanentSwitchOff:
1050+ actionString = " permanently switch off" ;
1051+ break ;
1052+ case HeaterProtectionAction::TemporarySwitchOff:
1053+ actionString = " temporarily switch off" ;
1054+ break ;
1055+ default :
1056+ actionString = " (undefined)" ;
1057+ break ;
1058+ }
1059+
1060+ switch (item.GetTrigger ())
1061+ {
1062+ case HeaterProtectionTrigger::TemperatureExceeded:
1063+ triggerString = " exceeds" ;
1064+ break ;
1065+ case HeaterProtectionTrigger::TemperatureTooLow:
1066+ triggerString = " falls below" ;
1067+ break ;
1068+ default :
1069+ triggerString = " (undefined)" ;
1070+ break ;
1071+ }
1072+
1073+ reply.printf (" Temperature protection item %d is configured for heater %d and uses sensor %d to %s if the temperature %s %.1f" DEGREE_SYMBOL " C" ,
1074+ index, item.GetHeater (), item.GetSensorNumber (), actionString, triggerString, (double )item.GetTemperatureLimit ());
1075+ }
1076+ }
1077+
1078+ return GCodeResult::ok;
9791079}
9801080
981- // Updates the PIDs and HeaterProtection items after a heater change
982- void Heat::UpdateHeaterProtection ()
1081+ // Updates the PIDs and HeaterProtection items after a heater change. Caller must already have a write lock on the heaters.
1082+ void Heat::UpdateHeaterProtection (int heaterNumber )
9831083{
984- ReadLocker lock (heatersLock);
985-
986- // Reassign the first mapped heater protection item of each PID where applicable
987- // and rebuild the linked list of heater protection elements per heater
988- for (size_t heater : ARRAY_INDICES (heaters))
1084+ auto h = FindHeater (heaterNumber);
1085+ if (h.IsNotNull ())
9891086 {
9901087 // Rebuild linked lists
1088+ h->SetHeaterProtection (nullptr );
9911089 HeaterProtection *firstProtectionItem = nullptr ;
9921090 HeaterProtection *lastElementInList = nullptr ;
9931091 for (HeaterProtection *prot : heaterProtections)
9941092 {
995- if (prot->GetHeater () == ( int )heater )
1093+ if (prot->GetHeater () == heaterNumber )
9961094 {
9971095 if (firstProtectionItem == nullptr )
9981096 {
@@ -1012,11 +1110,7 @@ void Heat::UpdateHeaterProtection()
10121110 }
10131111 }
10141112
1015- // Update reference to the first item so that we can achieve better performance
1016- if (heaters[heater] != nullptr )
1017- {
1018- heaters[heater]->SetHeaterProtection (firstProtectionItem);
1019- }
1113+ h->SetHeaterProtection (firstProtectionItem);
10201114 }
10211115}
10221116
0 commit comments