1 // 2 // Copyright (c) 2010-2024 Antmicro 3 // Copyright (c) 2011-2015 Realtime Embedded 4 // 5 // This file is licensed under the MIT License. 6 // Full license text is available in 'licenses/MIT.txt'. 7 // 8 using System; 9 using Antmicro.Renode.Utilities; 10 11 namespace Antmicro.Renode.Core.Structure.Registers 12 { 13 public static class PeripheralRegisterExtensions 14 { 15 /// <summary> 16 /// Creates a fluent conditional wrapper for conditionally executing actions on a register. 17 /// </summary> 18 /// <param name="condition">The condition to evaluate.</param> 19 /// <returns>An <see cref="IfWrapper{T}"/> object wrapping the register.</returns> 20 /// <example> 21 /// This example demonstrates how to use the <c>If</c> and <c>Else</c> methods 22 /// of <see cref="IfWrapper{T}"/> to conditionally define a field on a register: 23 /// <code> 24 /// Registers.Control.Define(this) 25 /// .WithValueField(0, 4, out transmissionSize, name: "TXSIZE") 26 /// .If(SupportsEncryption) 27 /// .Then(r => r.WithValueField(4, 12, out transmissionKey, name: "TXKEY")) 28 /// .Else(r => r.WithReservedBits(4, 12)); 29 /// </code> 30 /// </example> 31 public static IfWrapper<T> If<T>(this T register, bool condition) where T : PeripheralRegister 32 { 33 return new IfWrapper<T>(register, condition); 34 } 35 36 /// <summary> 37 /// Fluent API for handling for loops. This helper is equivalent to calling the callback in a for loop 38 /// going from "start" to "end" being incremented by "step" 39 /// </summary> 40 /// <param name="callback">Callback to execute on each loop iteration</param> 41 /// <param name="start">Starting value of the loop variable</param> 42 /// <param name="end">Exclusive ending value of the loop variable</param> 43 /// <param name="step">Amount that the loop variable will be incremented by after each iteration</param> 44 /// <returns>This register after all loop iterations</returns> 45 public static T For<T>(this T register, Action<T, int> callback, int start, int end, int step = 1) where T : PeripheralRegister 46 { 47 for(var i = start; i < end; i += step) 48 { 49 callback(register, i); 50 } 51 return register; 52 } 53 54 /// <summary> 55 /// Fluent API for flag field creation. For parameters see <see cref="PeripheralRegister.DefineFlagField"/>. 56 /// </summary> 57 /// <returns>This register with a defined flag.</returns> 58 public static T WithFlag<T>(this T register, int position, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<bool, bool> readCallback = null, 59 Action<bool, bool> writeCallback = null, Action<bool, bool> changeCallback = null, Func<bool, bool> valueProviderCallback = null, bool softResettable = true, 60 string name = null) where T : PeripheralRegister 61 { 62 register.DefineFlagField(position, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name); 63 return register; 64 } 65 66 /// <summary> 67 /// Fluent API for creation of a set of consecutive flag fields. 68 /// </summary> 69 /// <param name="position">Offset in the register of the first field.</param> 70 /// <param name="count">Number of flag fields to create.</param> 71 /// <param name="mode">Access modifiers of each field.</param> 72 /// <param name="readCallback">Method to be called whenever the containing register is read. The first parameter is the index of the flag field, the second is the value of this field before read, 73 /// the third parameter is the value after read. Note that it will also be called for unreadable fields.</param> 74 /// <param name="writeCallback">Method to be called whenever the containing register is written to. The first parameter is the index of the flag, the second is the value of this field before write, 75 /// the third parameter is the value written (without any modification). Note that it will also be called for unwrittable fields.</param> 76 /// <param name="changeCallback">Method to be called whenever this field's value is changed, either due to read or write. The first parameter is the index of the flag, the second is the value of this field before change, 77 /// the third parameter is the value after change. Note that it will also be called for unwrittable fields.</param> 78 /// <param name="valueProviderCallback">Method to be called whenever this field is read. The value passed is the current field's value, that will be overwritten by 79 /// the value returned from it. This returned value is eventually passed as the second parameter of <paramref name="readCallback"/>.</param> 80 /// <param name="softResettable">Indicates whether the field should be cleared by soft reset.</param> 81 /// <param name="name">Ignored parameter, for convenience. Treat it as a comment.</param> 82 /// <returns>This register with defined flags.</returns> 83 public static T WithFlags<T>(this T register, int position, int count, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<int, bool, bool> readCallback = null, 84 Action<int, bool, bool> writeCallback = null, Action<int, bool, bool> changeCallback = null, Func<int, bool, bool> valueProviderCallback = null, bool softResettable = true, 85 string name = null) where T : PeripheralRegister 86 { 87 return WithFlags(register, position, count, out var _, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name); 88 } 89 90 /// <summary> 91 /// Fluent API for value field creation. For parameters see <see cref="PeripheralRegister.DefineValueField"/>. 92 /// </summary> 93 /// <returns>This register with a defined value field.</returns> 94 public static T WithValueField<T>(this T register, int position, int width, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<ulong, ulong> readCallback = null, 95 Action<ulong, ulong> writeCallback = null, Action<ulong, ulong> changeCallback = null, Func<ulong, ulong> valueProviderCallback = null, bool softResettable = true, 96 string name = null) where T : PeripheralRegister 97 { 98 register.DefineValueField(position, width, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name); 99 return register; 100 } 101 102 /// <summary> 103 /// Fluent API for creation of a set of consecutive value fields 104 /// </summary> 105 /// <param name="position">Offset in the register of the first field.</param> 106 /// <param name="width">Maximum width of the value, in terms of binary representation.</param> 107 /// <param name="count">Number of flag fields to create.</param> 108 /// <param name="mode">Access modifiers of each field.</param> 109 /// <param name="readCallback">Method to be called whenever the containing register is read. The first parameter is the index of the value field, the second is the value of this field before read, 110 /// the third parameter is the value after read. Note that it will also be called for unreadable fields.</param> 111 /// <param name="writeCallback">Method to be called whenever the containing register is written to. The first parameter is the index of the field, the second is the value of this field before write, 112 /// the third parameter is the value written (without any modification). Note that it will also be called for unwrittable fields.</param> 113 /// <param name="changeCallback">Method to be called whenever this field's value is changed, either due to read or write. The first parameter is the index of the field, the second is the value of this field before change, 114 /// the third parameter is the value after change. Note that it will also be called for unwrittable fields.</param> 115 /// <param name="valueProviderCallback">Method to be called whenever this field is read. The value passed is the current field's value, that will be overwritten by 116 /// the value returned from it. This returned value is eventually passed as the second parameter of <paramref name="readCallback"/>.</param> 117 /// <param name="softResettable">Indicates whether the field should be cleared by soft reset.</param> 118 /// <param name="name">Ignored parameter, for convenience. Treat it as a comment.</param> 119 /// <returns>This register with defined value fields.</returns> 120 public static T WithValueFields<T>(this T register, int position, int width, int count, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<int, ulong, ulong> readCallback = null, 121 Action<int, ulong, ulong> writeCallback = null, Action<int, ulong, ulong> changeCallback = null, Func<int, ulong, ulong> valueProviderCallback = null, bool softResettable = true, 122 string name = null) where T : PeripheralRegister 123 { 124 return WithValueFields(register, position, width, count, out var _, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name); 125 } 126 127 /// <summary> 128 /// Fluent API for enum field creation. For parameters see <see cref="PeripheralRegister.DefineEnumField"/>. 129 /// </summary> 130 /// <returns>This register with a defined enum field.</returns> 131 public static R WithEnumField<R, T>(this R register, int position, int width, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<T, T> readCallback = null, 132 Action<T, T> writeCallback = null, Action<T, T> changeCallback = null, Func<T, T> valueProviderCallback = null, bool softResettable = true, string name = null) 133 where R : PeripheralRegister 134 where T : struct, IConvertible 135 { register.DefineEnumFieldAntmicro.Renode.Core.Structure.Registers.PeripheralRegisterExtensions.IConvertible136 register.DefineEnumField<T>(position, width, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name); 137 return register; 138 } 139 140 /// <summary> 141 /// Fluent API for tagged field creation. For parameters see <see cref="PeripheralRegister.Tag"/>. 142 /// </summary> 143 /// <returns>This register with a defined tag field.</returns> 144 public static T WithTag<T>(this T register, string name, int position, int width) where T : PeripheralRegister 145 { 146 register.Tag(name, position, width); 147 return register; 148 } 149 150 /// <summary> 151 /// Fluent API for creating a set of tagged fields. For parameters see <see cref="PeripheralRegister.Tag"/>. 152 /// </summary> 153 /// <returns>This register with a defined tag field set.</returns> 154 public static T WithTags<T>(this T register, string name, int position, int width, int count) where T : PeripheralRegister 155 { 156 for(var i = 0; i < count; i++) 157 { 158 register.Tag(name == null ? null : $"{name}_{i}", position + (i * width), width); 159 } 160 return register; 161 } 162 163 /// <summary> 164 /// Fluent API for tagged flag creation - a tag of width equal to 1. For parameters see <see cref="PeripheralRegister.DefineValueField"/>. 165 /// </summary> 166 /// <returns>This register with a defined tag field.</returns> 167 public static T WithTaggedFlag<T>(this T register, string name, int position) where T : PeripheralRegister 168 { 169 register.Tag(name, position, 1); 170 return register; 171 } 172 173 /// <summary> 174 /// Fluent API for creating a set of tagged flags - a tag of width equal to 1. For parameters see <see cref="PeripheralRegister.DefineValueField"/>. 175 /// </summary> 176 /// <returns>This register with a defined tag field set.</returns> 177 public static T WithTaggedFlags<T>(this T register, string name, int position, int count) where T : PeripheralRegister 178 { 179 for(var i = 0; i < count; i++) 180 { 181 register.WithTaggedFlag(name == null ? null : $"{name}_{i}", position + i); 182 } 183 return register; 184 } 185 186 /// <summary> 187 /// Fluent API for value field creation. For parameters see <see cref="PeripheralRegister.DefineValueField"/>. 188 /// This overload allows you to retrieve the created field via <c>valueField</c> parameter. 189 /// </summary> 190 /// <returns>This register with a defined value field.</returns> 191 public static T WithValueField<T>(this T register, int position, int width, out IValueRegisterField valueField, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<ulong, ulong> readCallback = null, 192 Action<ulong, ulong> writeCallback = null, Action<ulong, ulong> changeCallback = null, Func<ulong, ulong> valueProviderCallback = null, bool softResettable = true, string name = null) where T : PeripheralRegister 193 { 194 valueField = register.DefineValueField(position, width, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name); 195 return register; 196 } 197 198 /// <summary> 199 /// Fluent API for creation of set of value fields. For parameters see the other overload of <see cref="PeripheralRegisterExtensions.WithValueFields"/>. 200 /// This overload allows you to retrieve the created array of fields via <c>valueFields</c> parameter. 201 /// </summary> 202 /// <returns>This register with defined value fields.</returns> 203 public static T WithValueFields<T>(this T register, int position, int width, int count, out IValueRegisterField[] valueFields, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<int, ulong, ulong> readCallback = null, 204 Action<int, ulong, ulong> writeCallback = null, Action<int, ulong, ulong> changeCallback = null, Func<int, ulong, ulong> valueProviderCallback = null, bool softResettable = true, 205 string name = null) where T : PeripheralRegister 206 { 207 valueFields = new IValueRegisterField[count]; 208 for(var i = 0; i < count; i++) 209 { 210 var j = i; 211 212 valueFields[j] = register.DefineValueField(position + (j * width), width, mode, 213 readCallback == null ? null : (Action<ulong, ulong>)((x, y) => readCallback(j, x, y)), 214 writeCallback == null ? null : (Action<ulong, ulong>)((x, y) => writeCallback(j, x, y)), 215 changeCallback == null ? null : (Action<ulong, ulong>)((x, y) => changeCallback(j, x, y)), 216 valueProviderCallback == null ? null : (Func<ulong, ulong>)((x) => valueProviderCallback(j, x)), 217 softResettable, 218 name == null ? null : $"{name}_{j}"); 219 } 220 return register; 221 } 222 223 /// <summary> 224 /// Fluent API for enum field creation. For parameters see <see cref="PeripheralRegister.DefineEnumField"/>. 225 /// This overload allows you to retrieve the created field via <c>enumField</c> parameter. 226 /// </summary> 227 /// <returns>This register with a defined enum field.</returns> 228 public static R WithEnumField<R, T>(this R register, int position, int width, out IEnumRegisterField<T> enumField, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<T, T> readCallback = null, 229 Action<T, T> writeCallback = null, Action<T, T> changeCallback = null, Func<T, T> valueProviderCallback = null, bool softResettable = true, string name = null) where R : PeripheralRegister 230 where T : struct, IConvertible 231 { 232 enumField = register.DefineEnumField<T>(position, width, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name); 233 return register; 234 } 235 236 /// <summary> 237 /// Fluent API for creation of set of enum fields. For parameters see the other overload of <see cref="PeripheralRegisterExtensions.WithEnumFields"/>. 238 /// This overload allows you to retrieve the created array of fields via <c>enumFields</c> parameter. 239 /// </summary> 240 /// <returns>This register with defined enum fields.</returns> 241 public static R WithEnumFields<R, T>(this R register, int position, int width, int count, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<int, T, T> readCallback = null, 242 Action<int, T, T> writeCallback = null, Action<int, T, T> changeCallback = null, Func<int, T, T> valueProviderCallback = null, bool softResettable = true, string name = null) 243 where R : PeripheralRegister 244 where T : struct, IConvertible 245 { 246 return WithEnumFields<R, T>(register, position, width, count, out var _, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name); 247 } 248 249 /// <summary> 250 /// Fluent API for creation of set of enum fields. For parameters see the other overload of <see cref="PeripheralRegisterExtensions.WithEnumFields"/>. 251 /// This overload allows you to retrieve the created array of fields via <c>enumFields</c> parameter. 252 /// </summary> 253 /// <returns>This register with defined enum fields.</returns> 254 public static R WithEnumFields<R, T>(this R register, int position, int width, int count, out IEnumRegisterField<T>[] enumFields, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<int, T, T> readCallback = null, 255 Action<int, T, T> writeCallback = null, Action<int, T, T> changeCallback = null, Func<int, T, T> valueProviderCallback = null, bool softResettable = true, string name = null) 256 where R : PeripheralRegister 257 where T : struct, IConvertible 258 { 259 enumFields = new IEnumRegisterField<T>[count]; 260 for(var i = 0; i < count; i++) 261 { 262 var j = i; 263 264 enumFields[j] = register.DefineEnumField<T>(position + (j * width), width, mode, 265 readCallback == null ? null : (Action<T, T>)((x, y) => readCallback(j, x, y)), 266 writeCallback == null ? null : (Action<T, T>)((x, y) => writeCallback(j, x, y)), 267 changeCallback == null ? null : (Action<T, T>)((x, y) => changeCallback(j, x, y)), 268 valueProviderCallback == null ? null : (Func<T, T>)((x) => valueProviderCallback(j, x)), 269 softResettable, 270 name == null ? null : $"{name}_{j}"); 271 } 272 return register; 273 } 274 275 /// <summary> 276 /// Fluent API for flag field creation. For parameters see <see cref="PeripheralRegister.DefineFlagField"/>. 277 /// This overload allows you to retrieve the created field via <c>flagField</c> parameter. 278 /// </summary> 279 /// <returns>This register with a defined flag.</returns> 280 public static T WithFlag<T>(this T register, int position, out IFlagRegisterField flagField, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<bool, bool> readCallback = null, 281 Action<bool, bool> writeCallback = null, Action<bool, bool> changeCallback = null, Func<bool, bool> valueProviderCallback = null, bool softResettable = true, string name = null) 282 where T : PeripheralRegister 283 { 284 flagField = register.DefineFlagField(position, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name); 285 return register; 286 } 287 288 /// <summary> 289 /// Fluent API for creation of sets of flag fields. For parameters see the other overload of <see cref="PeripheralRegisterExtensions.WithFlags"/>. 290 /// This overload allows you to retrieve the created array of fields via <c>flagFields</c> parameter. 291 /// </summary> 292 /// <returns>This register with defined flags.</returns> 293 public static T WithFlags<T>(this T register, int position, int count, out IFlagRegisterField[] flagFields, FieldMode mode = FieldMode.Read | FieldMode.Write, Action<int, bool, bool> readCallback = null, 294 Action<int, bool, bool> writeCallback = null, Action<int, bool, bool> changeCallback = null, Func<int, bool, bool> valueProviderCallback = null, bool softResettable = true, 295 string name = null) where T : PeripheralRegister 296 { 297 flagFields = new IFlagRegisterField[count]; 298 for(var i = 0; i < count; i++) 299 { 300 var j = i; 301 302 flagFields[j] = register.DefineFlagField(position + j, mode, 303 readCallback == null ? null : (Action<bool, bool>)((x, y) => readCallback(j, x, y)), 304 writeCallback == null ? null : (Action<bool, bool>)((x, y) => writeCallback(j, x, y)), 305 changeCallback == null ? null : (Action<bool, bool>)((x, y) => changeCallback(j, x, y)), 306 valueProviderCallback == null ? null : (Func<bool, bool>)((x) => valueProviderCallback(j, x)), 307 softResettable, 308 name == null ? null : $"{name}_{j}"); 309 } 310 return register; 311 } 312 313 /// <summary> 314 /// Fluent API for tagging bits as "RESERVED". For description see <see cref="PeripheralRegister.Reserved"/>. 315 /// </summary> 316 /// <returns>This register with a new "RESERVED" tag.</returns> 317 public static T WithReservedBits<T>(this T register, int position, int width, uint? allowedValue = null) where T : PeripheralRegister 318 { 319 register.Reserved(position, width, allowedValue); 320 return register; 321 } 322 323 /// <summary> 324 /// Fluent API for tagging bits as ignored. 325 /// </summary> 326 /// <returns>This defines a value field to avoid warnings about unhandled bits.</returns> 327 public static T WithIgnoredBits<T>(this T register, int position, int width) where T : PeripheralRegister 328 { 329 return register.WithValueField(position, width, name: "ignored"); 330 } 331 } 332 333 public static class QuadWordRegisterExtensions 334 { 335 /// <summary> 336 /// Fluent API for read callback registration. For description see <see cref="QuadWordRegister.DefineReadCallback"/>. 337 /// </summary> 338 /// <returns>This register with a defined callback.</returns> WithReadCallback(this QuadWordRegister register, Action<ulong, ulong> readCallback)339 public static QuadWordRegister WithReadCallback(this QuadWordRegister register, Action<ulong, ulong> readCallback) 340 { 341 register.DefineReadCallback(readCallback); 342 return register; 343 } 344 345 /// <summary> 346 /// Fluent API for write callback registration. For description see <see cref="QuadWordRegister.DefineWriteCallback"/>. 347 /// </summary> 348 /// <returns>This register with a defined callback.</returns> WithWriteCallback(this QuadWordRegister register, Action<ulong, ulong> writeCallback)349 public static QuadWordRegister WithWriteCallback(this QuadWordRegister register, Action<ulong, ulong> writeCallback) 350 { 351 register.DefineWriteCallback(writeCallback); 352 return register; 353 } 354 355 /// <summary> 356 /// Fluent API for change callback registration. For description see <see cref="QuadWordRegister.DefineChangeCallback"/>. 357 /// </summary> 358 /// <returns>This register with a defined callback.</returns> WithChangeCallback(this QuadWordRegister register, Action<ulong, ulong> changeCallback)359 public static QuadWordRegister WithChangeCallback(this QuadWordRegister register, Action<ulong, ulong> changeCallback) 360 { 361 register.DefineChangeCallback(changeCallback); 362 return register; 363 } 364 } 365 366 public static class DoubleWordRegisterExtensions 367 { 368 /// <summary> 369 /// Fluent API for read callback registration. For description see <see cref="DoubleWordRegister.DefineReadCallback"/>. 370 /// </summary> 371 /// <returns>This register with a defined callback.</returns> WithReadCallback(this DoubleWordRegister register, Action<uint, uint> readCallback)372 public static DoubleWordRegister WithReadCallback(this DoubleWordRegister register, Action<uint, uint> readCallback) 373 { 374 register.DefineReadCallback(readCallback); 375 return register; 376 } 377 378 /// <summary> 379 /// Fluent API for write callback registration. For description see <see cref="DoubleWordRegister.DefineWriteCallback"/>. 380 /// </summary> 381 /// <returns>This register with a defined callback.</returns> WithWriteCallback(this DoubleWordRegister register, Action<uint, uint> writeCallback)382 public static DoubleWordRegister WithWriteCallback(this DoubleWordRegister register, Action<uint, uint> writeCallback) 383 { 384 register.DefineWriteCallback(writeCallback); 385 return register; 386 } 387 388 /// <summary> 389 /// Fluent API for change callback registration. For description see <see cref="DoubleWordRegister.DefineChangeCallback"/>. 390 /// </summary> 391 /// <returns>This register with a defined callback.</returns> WithChangeCallback(this DoubleWordRegister register, Action<uint, uint> changeCallback)392 public static DoubleWordRegister WithChangeCallback(this DoubleWordRegister register, Action<uint, uint> changeCallback) 393 { 394 register.DefineChangeCallback(changeCallback); 395 return register; 396 } 397 } 398 399 public static class WordRegisterExtensions 400 { 401 /// <summary> 402 /// Fluent API for read callback registration. For description see <see cref="WordRegister.DefineReadCallback"/>. 403 /// </summary> 404 /// <returns>This register with a defined callback.</returns> WithReadCallback(this WordRegister register, Action<ushort, ushort> readCallback)405 public static WordRegister WithReadCallback(this WordRegister register, Action<ushort, ushort> readCallback) 406 { 407 register.DefineReadCallback(readCallback); 408 return register; 409 } 410 411 /// <summary> 412 /// Fluent API for write callback registration. For description see <see cref="WordRegister.DefineWriteCallback"/>. 413 /// </summary> 414 /// <returns>This register with a defined callback.</returns> WithWriteCallback(this WordRegister register, Action<ushort, ushort> writeCallback)415 public static WordRegister WithWriteCallback(this WordRegister register, Action<ushort, ushort> writeCallback) 416 { 417 register.DefineWriteCallback(writeCallback); 418 return register; 419 } 420 421 /// <summary> 422 /// Fluent API for change callback registration. For description see <see cref="WordRegister.DefineChangeCallback"/>. 423 /// </summary> 424 /// <returns>This register with a defined callback.</returns> WithChangeCallback(this WordRegister register, Action<ushort, ushort> changeCallback)425 public static WordRegister WithChangeCallback(this WordRegister register, Action<ushort, ushort> changeCallback) 426 { 427 register.DefineChangeCallback(changeCallback); 428 return register; 429 } 430 } 431 432 public static class ByteRegisterExtensions 433 { 434 /// <summary> 435 /// Fluent API for read callback registration. For description see <see cref="ByteRegister.DefineReadCallback"/>. 436 /// </summary> 437 /// <returns>This register with a defined callback.</returns> WithReadCallback(this ByteRegister register, Action<byte, byte> readCallback)438 public static ByteRegister WithReadCallback(this ByteRegister register, Action<byte, byte> readCallback) 439 { 440 register.DefineReadCallback(readCallback); 441 return register; 442 } 443 444 /// <summary> 445 /// Fluent API for write callback registration. For description see <see cref="ByteRegister.DefineWriteCallback"/>. 446 /// </summary> 447 /// <returns>This register with a defined callback.</returns> WithWriteCallback(this ByteRegister register, Action<byte, byte> writeCallback)448 public static ByteRegister WithWriteCallback(this ByteRegister register, Action<byte, byte> writeCallback) 449 { 450 register.DefineWriteCallback(writeCallback); 451 return register; 452 } 453 454 /// <summary> 455 /// Fluent API for change callback registration. For description see <see cref="ByteRegister.DefineChangeCallback"/>. 456 /// </summary> 457 /// <returns>This register with a defined callback.</returns> WithChangeCallback(this ByteRegister register, Action<byte, byte> changeCallback)458 public static ByteRegister WithChangeCallback(this ByteRegister register, Action<byte, byte> changeCallback) 459 { 460 register.DefineChangeCallback(changeCallback); 461 return register; 462 } 463 } 464 } 465