tmcl/
instructions.rs

1//! TMCL Instructions
2
3#[cfg(feature="std")]
4use std::marker::PhantomData;
5#[cfg(not(feature="std"))]
6use core::marker::PhantomData;
7
8use {
9    WriteableAxisParameter,
10    ReadableAxisParameter,
11};
12
13/// A `TMCL` `Instruction`
14pub trait Instruction {
15    /// The command number (sometimes referred to as the instruction number).
16    const INSTRUCTION_NUMBER: u8;
17
18    fn type_number(&self) -> u8;
19
20    /// The motor/bank number
21    fn motor_bank_number(&self) -> u8;
22
23    /// Return the operand serialized.
24    ///
25    /// Even though the whole frame (in serialized form) is represented as:
26    /// `[..., operand[3], operand[2], operand[1], operand[0], ...]`.
27    /// This function instead return the operand:
28    /// `[operand[0], operand[1], operand[2], operand[3]]`.
29    fn operand(&self) -> [u8; 4];
30}
31
32/// An `Instruction` useable in direct mode
33pub trait DirectInstruction: Instruction {
34    /// The return value when the `Instruction` is executed in direct mode.
35    type Return: Return;
36}
37
38/// A type that can be used as a return value for an `Instruction`
39pub trait Return {
40
41    /// The deserialization function.
42    ///
43    /// The argument of the deserialize function is the operand bytes array:
44    /// `[operand[0], operand[1], operand[2], operand[3]]`.
45    /// This is a different to how it is represented in the serialized frame:
46    /// `[..., operand[3], operand[2], operand[1], operand[0], ...]`
47    fn from_operand(operand: [u8; 4]) -> Self;
48}
49
50/// ROR - Rotate Right
51///
52/// This instruction starts rotation in "right" direction, i.e. increasing the position counter.
53#[derive(Debug, PartialEq)]
54pub struct ROR {
55    motor_number: u8,
56    velocity: u32,
57}
58impl ROR {
59    pub fn new(motor_number: u8, velocity: u32) -> ROR {ROR{motor_number, velocity}}
60}
61impl Instruction for ROR {
62    const INSTRUCTION_NUMBER: u8 = 1;
63
64    fn operand(&self) -> [u8; 4] {
65        return [
66            (self.velocity & 0xff) as u8,
67            ((self.velocity >> 8) & 0xff) as u8,
68            ((self.velocity >> 16) & 0xff) as u8,
69            ((self.velocity >> 24) & 0xff) as u8
70        ]
71    }
72
73    fn type_number(&self) -> u8 {
74        0
75    }
76
77    fn motor_bank_number(&self) -> u8 {
78        self.motor_number
79    }
80}
81impl DirectInstruction for ROR {
82    type Return = ();
83}
84
85/// ROL - Rotate Left
86///
87/// This instruction starts rotation in "left" direction, i.e. decreasing the position counter.
88#[derive(Debug, PartialEq)]
89pub struct ROL {
90    motor_number: u8,
91    velocity: u32,
92}
93impl ROL {
94    pub fn new(motor_number: u8, velocity: u32) -> ROL {ROL{motor_number, velocity}}
95}
96impl Instruction for ROL {
97    const INSTRUCTION_NUMBER: u8 = 2;
98
99    fn operand(&self) -> [u8; 4] {
100        return [
101            (self.velocity & 0xff) as u8,
102            ((self.velocity >> 8) & 0xff) as u8,
103            ((self.velocity >> 16) & 0xff) as u8,
104            ((self.velocity >> 24) & 0xff) as u8
105        ]
106    }
107
108    fn type_number(&self) -> u8 {
109        0
110    }
111
112    fn motor_bank_number(&self) -> u8 {
113        self.motor_number
114    }
115}
116impl DirectInstruction for ROL {
117    type Return = ();
118}
119
120
121/// MST - Motor Stop
122///
123/// This instruction stops the motor.
124#[derive(Debug, PartialEq)]
125pub struct MST {
126    motor_number: u8,
127}
128impl MST {
129    pub fn new(motor_number: u8) -> MST {MST{motor_number}}
130}
131impl Instruction for MST {
132    const INSTRUCTION_NUMBER: u8 = 3;
133
134    fn operand(&self) -> [u8; 4] {
135        return [0, 0, 0, 0]
136    }
137
138    fn type_number(&self) -> u8 {
139        0
140    }
141
142    fn motor_bank_number(&self) -> u8 {
143        self.motor_number
144    }
145}
146impl DirectInstruction for MST {
147    type Return = ();
148}
149
150/// The type and value of a `MVP` instruction
151#[derive(Debug, PartialEq, Clone, Copy)]
152pub enum MoveOperation {
153    /// Moving to an absolute position in the range from -8388608 to +8388608 (-2^23 to +2^23).
154    Absolute(i32),
155
156    /// Starting a relative movement by means of an offset to the actual position. In this case,
157    /// the resulting new position value must not exceed the above mentioned limits, too.
158    Relative(i32),
159
160    /// Moving one or more motors to a (previously stored) coordinate (represented by a coordinate number),
161    ///
162    /// When moving more than one axis the  module will try  to  interpolate:
163    /// The velocities will be calculated so that  all  motors reach their target positions at the same time.
164    /// It is important that the maximum accelerations (axis parameter #5) and the ramp  and
165    /// pulse dividers (axis parameters #153 and #154) of all axes are set to the same values
166    /// as otherwise interpolation will not work correctly.
167    Coordinate(u32),
168}
169
170/// MVP - Move to Position
171///
172/// A movement towards the specified position is started, with automatic generation of acceleration
173/// and deceleration ramps. The maximum velocity and acceleration are defined by axis parameters #4 and #5.
174#[derive(Debug, PartialEq)]
175pub struct MVP {
176    motor_number: u8,
177    value: MoveOperation,
178}
179impl MVP {
180    pub fn new(motor_number: u8, value: MoveOperation) -> MVP {MVP{motor_number, value}}
181}
182impl Instruction for MVP {
183    const INSTRUCTION_NUMBER: u8 = 4;
184
185    fn operand(&self) -> [u8; 4] {
186        match self.value {
187            MoveOperation::Absolute(x) => {
188                [
189                    (x & 0xff) as u8,
190                    ((x >> 8) & 0xff) as u8,
191                    ((x >> 16) & 0xff) as u8,
192                    ((x >> 24) & 0xff) as u8
193                ]
194            },
195            MoveOperation::Relative(x) => {
196                [
197                    (x & 0xff) as u8,
198                    ((x >> 8) & 0xff) as u8,
199                    ((x >> 16) & 0xff) as u8,
200                    ((x >> 24) & 0xff) as u8
201                ]
202            },
203            MoveOperation::Coordinate(x) => {
204                [
205                    (x & 0xff) as u8,
206                    ((x >> 8) & 0xff) as u8,
207                    ((x >> 16) & 0xff) as u8,
208                    ((x >> 24) & 0xff) as u8
209                ]
210            },
211        }
212    }
213
214    fn type_number(&self) -> u8 {
215        0
216    }
217
218    fn motor_bank_number(&self) -> u8 {
219        self.motor_number
220    }
221}
222impl DirectInstruction for MVP {
223    type Return = ();
224}
225
226
227/// SAP - Set Axis Parameter
228///
229/// Most parameters of a TMCM module can be adjusted individually for each axis.
230/// Although  these parameters vary widely in their formats (1 to 24 bits, signed or unsigned)
231/// and physical locations (TMC428, TMC453, controller RAM, controller EEPROM),
232/// they all can be set by this function.
233#[derive(Debug, PartialEq)]
234pub struct SAP<T: WriteableAxisParameter> {
235    motor_number: u8,
236    axis_parameter: T,
237}
238impl<T: WriteableAxisParameter> SAP<T> {
239    pub fn new(motor_number: u8, axis_parameter: T) -> SAP<T> {
240        SAP{
241            motor_number,
242            axis_parameter
243        }
244    }
245}
246impl<T: WriteableAxisParameter> Instruction for SAP<T> {
247    const INSTRUCTION_NUMBER: u8 = 5;
248
249    fn operand(&self) -> [u8; 4] {
250        self.axis_parameter.operand()
251    }
252
253    fn type_number(&self) -> u8 {
254        T::NUMBER
255    }
256
257    fn motor_bank_number(&self) -> u8 {
258        self.motor_number
259    }
260}
261impl<T: WriteableAxisParameter> DirectInstruction for SAP<T> {
262    type Return = ();
263}
264
265/// GAP - Get Axis Parameter
266///
267/// Most parameters of a TMCM module can be adjusted individually for each axis.
268/// Although  these parameters vary widely in their formats (1 to 24 bits, signed or unsigned)
269/// and physical locations (TMC428, TMC453, controller RAM, controller EEPROM),
270/// they all can be read by this function.
271#[derive(Debug, PartialEq)]
272pub struct GAP<T: ReadableAxisParameter> {
273    motor_number: u8,
274    phantom: PhantomData<T>,
275}
276impl<T: ReadableAxisParameter> GAP<T> {
277    pub fn new(motor_number: u8) -> GAP<T> {
278        GAP{
279            motor_number,
280            phantom: PhantomData,
281        }
282    }
283}
284impl<T: ReadableAxisParameter> Instruction for GAP<T> {
285    const INSTRUCTION_NUMBER: u8 = 6;
286
287    fn operand(&self) -> [u8; 4] {
288        [0u8, 0u8, 0u8, 0u8]
289    }
290
291    fn type_number(&self) -> u8 {
292        T::NUMBER
293    }
294
295    fn motor_bank_number(&self) -> u8 {
296        self.motor_number
297    }
298}
299impl<T: ReadableAxisParameter> DirectInstruction for GAP<T> {
300    type Return = T;
301}
302
303/// STAP - Store Axis Parameter
304///
305/// Axis parameters are located in RAM memory, so modifications are lost at power down.
306/// This instruction enables permanent storing.
307#[derive(Debug, PartialEq)]
308pub struct STAP<T: WriteableAxisParameter> {
309    motor_number: u8,
310    phantom: PhantomData<T>,
311}
312impl<T: WriteableAxisParameter> STAP<T> {
313    pub fn new(motor_number: u8) -> STAP<T> {
314        STAP{
315            motor_number,
316            phantom: PhantomData,
317        }
318    }
319}
320impl<T: WriteableAxisParameter> Instruction for STAP<T> {
321    const INSTRUCTION_NUMBER: u8 = 7;
322
323    fn operand(&self) -> [u8; 4] {
324        [0u8, 0u8, 0u8, 0u8]
325    }
326
327    fn type_number(&self) -> u8 {
328        T::NUMBER
329    }
330
331    fn motor_bank_number(&self) -> u8 {
332        self.motor_number
333    }
334}
335impl<T: WriteableAxisParameter> DirectInstruction for STAP<T> {
336    type Return = ();
337}
338
339/// RSAP - Restore Axis Parameter
340///
341/// For all configuration-related axis parameters, non-volatile memory locations are provided.
342/// By default, most parameters are automatically restored after power up (see axis parameter list in
343/// chapter 4). A single parameter that has been changed before can be reset by this instruction.
344#[derive(Debug, PartialEq)]
345pub struct RSAP<T: WriteableAxisParameter> {
346    motor_number: u8,
347    phantom: PhantomData<T>,
348}
349impl<T: WriteableAxisParameter> RSAP<T> {
350    pub fn new(motor_number: u8) -> RSAP<T> {
351        RSAP {
352            motor_number,
353            phantom: PhantomData,
354        }
355    }
356}
357impl<T: WriteableAxisParameter> Instruction for RSAP<T> {
358    const INSTRUCTION_NUMBER: u8 = 8;
359
360    fn operand(&self) -> [u8; 4] {
361        [0u8, 0u8, 0u8, 0u8]
362    }
363
364    fn type_number(&self) -> u8 {
365        T::NUMBER
366    }
367
368    fn motor_bank_number(&self) -> u8 {
369        self.motor_number
370    }
371}
372impl<T: WriteableAxisParameter> DirectInstruction for RSAP<T> {
373    type Return = ();
374}
375
376/// Choses what action to execute with the `RFS` instruction
377#[derive(Debug, PartialEq, Clone, Copy)]
378pub enum ReferenceSearchAction {
379    /// Start reference search
380    Start = 0,
381    /// Stop reference search
382    Stop = 1,
383    /// Get status
384    Status = 2,
385}
386
387/// RFS - Reference Search
388///
389/// A build-in reference point search algorithm can be started (and stopped). The reference search
390/// algorithm provides switching point calibration and three switch modes. The status of the
391/// reference search can also be queried to see if it has already finished. (In a TMCL program
392/// it is better to use the WAIT command to wait for the end of a reference search.)
393/// Please see the appropriate parameters in the axis parameter table to configure the
394/// reference search algorithm to meet your needs. The reference search can be started or stop
395/// ped, or the actual status of the reference search can be checked.
396#[derive(Debug, PartialEq)]
397pub struct RFS {
398    motor_number: u8,
399    action: ReferenceSearchAction,
400}
401impl RFS {
402    pub fn new(motor_number: u8, action: ReferenceSearchAction) -> RFS {
403        RFS {
404            motor_number,
405            action
406        }
407    }
408}
409impl Instruction for RFS {
410    const INSTRUCTION_NUMBER: u8 = 13;
411
412    fn operand(&self) -> [u8; 4] {
413        [0u8, 0u8, 0u8, 0u8]
414    }
415
416    fn type_number(&self) -> u8 {
417        self.action as u8
418    }
419
420    fn motor_bank_number(&self) -> u8 {
421        self.motor_number
422    }
423}
424impl DirectInstruction for RFS {
425    // TODO: use const generics (when it lands) to distinguish return between RFS<Status> and RFS<_>
426    type Return = bool;
427}
428
429/// SIO - Set Output
430///
431/// This command sets the status of a digital output either to low (0) or to high (1).
432#[derive(Debug, PartialEq)]
433pub struct SIO {
434    bank_number: u8,
435    port_number: u8,
436    state: bool,
437}
438impl SIO {
439    pub fn new(bank_number: u8, port_number: u8, state: bool) -> Self {
440        SIO {bank_number, port_number, state}
441    }
442}
443impl Instruction for SIO {
444    const INSTRUCTION_NUMBER: u8 = 14;
445
446    fn operand(&self) -> [u8; 4] {[self.state as u8, 0u8, 0u8, 0u8]}
447
448    fn type_number(&self) -> u8 { self.port_number }
449
450    fn motor_bank_number(&self) -> u8 { self.bank_number }
451}
452impl DirectInstruction for SIO {
453    type Return = ();
454}
455
456/// GIO - Get Input / Output
457///
458/// This function reads a digital or analogue input port. So, digital lines will read 0 and 1,
459/// while the ADC channels deliver their 10 bit result in the range of 0...1023. In stand-alone mode
460/// the requested value is copied to the "accumulator" (accu) for further processing purposes such
461/// as conditioned jumps. In  direct  mode the value is only output in the “value” field of the reply,
462/// without affecting the accumulator. The actual status of a digital output line can also be read.
463#[derive(Debug, PartialEq)]
464pub struct GIO {
465    bank_number: u8,
466    port_number: u8,
467}
468impl GIO {
469    pub fn new(bank_number: u8, port_number: u8) -> Self {
470        GIO {bank_number, port_number}
471    }
472}
473impl Instruction for GIO {
474    const INSTRUCTION_NUMBER: u8 = 15;
475
476    fn operand(&self) -> [u8; 4] {[0u8, 0u8, 0u8, 0u8]}
477
478    fn type_number(&self) -> u8 { self.port_number }
479
480    fn motor_bank_number(&self) -> u8 { self.bank_number }
481}
482impl DirectInstruction for GIO {
483    type Return = u32;
484}
485
486/// CALC - Calculate
487#[derive(Debug, PartialEq)]
488pub enum CALC {
489    /// Add the operand to the accumulator
490    Add(i32),
491
492    /// Subtract the operand from the accumulator
493    Sub(i32),
494
495    /// Multiply the accumulator by a the operand
496    Mul(i32),
497
498    /// Divide the accumulator by the operand
499    Div(i32),
500
501    /// Modulo divide the accumualtor by the operand
502    Mod(i32),
503
504    /// Logical and accumulator with operand
505    And(i32),
506
507    /// Logical or accumulator with operand
508    Or(i32),
509
510    /// Logical xor accumulator with operand
511    Xor(i32),
512
513    /// Logical invert accumulator
514    Not,
515
516    /// Load operand to accumulator
517    Load(i32),
518}
519
520impl Instruction for CALC {
521    const INSTRUCTION_NUMBER: u8 = 19;
522
523    fn operand(&self) -> [u8; 4] {
524        match self {
525            CALC::Add(x) => [(x >> 0) as u8, (x >> 8) as u8, (x >> 16) as u8, (x >> 24) as u8],
526            CALC::Sub(x) => [(x >> 0) as u8, (x >> 8) as u8, (x >> 16) as u8, (x >> 24) as u8],
527            CALC::Mul(x) => [(x >> 0) as u8, (x >> 8) as u8, (x >> 16) as u8, (x >> 24) as u8],
528            CALC::Div(x) => [(x >> 0) as u8, (x >> 8) as u8, (x >> 16) as u8, (x >> 24) as u8],
529            CALC::Mod(x) => [(x >> 0) as u8, (x >> 8) as u8, (x >> 16) as u8, (x >> 24) as u8],
530            CALC::And(x) => [(x >> 0) as u8, (x >> 8) as u8, (x >> 16) as u8, (x >> 24) as u8],
531            CALC::Or(x) => [(x >> 0) as u8, (x >> 8) as u8, (x >> 16) as u8, (x >> 24) as u8],
532            CALC::Xor(x) => [(x >> 0) as u8, (x >> 8) as u8, (x >> 16) as u8, (x >> 24) as u8],
533            CALC::Not => [0u8, 0u8, 0u8, 0u8],
534            CALC::Load(x) => [(x >> 0) as u8, (x >> 8) as u8, (x >> 16) as u8, (x >> 24) as u8],
535        }
536    }
537
538    fn type_number(&self) -> u8 {
539        match self {
540            CALC::Add(_) => 0,
541            CALC::Sub(_) => 1,
542            CALC::Mul(_) => 2,
543            CALC::Div(_) => 3,
544            CALC::Mod(_) => 4,
545            CALC::And(_) => 5,
546            CALC::Or(_) => 6,
547            CALC::Xor(_) => 7,
548            CALC::Not => 8,
549            CALC::Load(_) => 9,
550        }
551    }
552
553    fn motor_bank_number(&self) -> u8 { 0 }
554}
555impl DirectInstruction for CALC {
556    type Return = ();
557}