Modmata  v0
An arduino communications server using Modbus
Modmata.cpp
Go to the documentation of this file.
1 /*
2 Modmata
3 Copyright © 2023 char* teamName <shutche@siue.edu>
4 Licensed under LGPL-2.1
5 */
6 
7 /**
8  * @file Modmata.cpp
9  * @author Sam Hutcherson, Chase Wallendorff, Iris Astrid
10  * @brief Functions to access Modmata commands from arduino .ino files.
11  * @date 2023-04-06
12  */
13 
14 /**
15  * @example ModmataLCD.ino
16  * @example StandardModmata.ino
17  */
18 
19 #include "Modmata.h"
20 using namespace modmata;
21 
22 ModmataClass Modmata;
23 
24 /**
25  * @brief Begin listening for a Modmata connection over serial/USB
26  * @remark This is configured to be used between a host computer and Arduino Leonardo using a USB connector
27  * (hardwired in the case of the LattePanda Delta 3.) The Leonardo is different from most other Arduinos
28  * in the usage of the serial connection, so if you modify this code, please keep that in mind.
29  * @param baud Set the baud rate of the listening serial connection
30  */
31 void ModmataClass::begin(int baud) {
32  mb.config(&Serial, baud, SERIAL_8N1);
33  mb.setSlaveId(1);
34 
35  callbackFunctions[PINMODE] = &pinMode;
36  callbackFunctions[DIGITALWRITE] = &digitalWrite;
37  callbackFunctions[DIGITALREAD] = &digitalRead;
38  callbackFunctions[ANALOGWRITE] = &analogWrite;
39  callbackFunctions[ANALOGREAD] = &analogRead;
40 
41  callbackFunctions[SERVOATTACH] = &servoAttach;
42  callbackFunctions[SERVODETACH] = &servoDetach;
43  callbackFunctions[SERVOWRITE] = &servoWrite;
44  callbackFunctions[SERVOREAD] = &servoRead;
45 
46  callbackFunctions[WIREBEGIN] = &wireBegin;
47  callbackFunctions[WIREEND] = &wireEnd;
48  callbackFunctions[WIRECLOCK] = &wireSetClock;
49  callbackFunctions[WIREWRITE] = &wireWrite;
50  callbackFunctions[WIREREAD] = &wireRead;
51 
52  callbackFunctions[SPIBEGIN] = &spiBegin;
53  callbackFunctions[SPISETTINGS] = &spiSettings;
54  callbackFunctions[SPITRANSFER] = &spiTransferBuf;
55  callbackFunctions[SPIEND] = &spiEnd;
56 
57  // Command register
58  for(int i = 0; i < MAX_REG_COUNT; i++) {
59  mb.addHreg(i);
60  }
61 }
62 
63 /**
64  * @brief Assign a function to a command number. Standard commands have default functions,
65  * but those can be overwritten here, or more commands can be added.
66  * @param command The modbus command being assigned a function
67  * @param fn A pointer to the function to be called when the command is recieved
68  */
69 void ModmataClass::attach(uint8_t command, struct registers (*fn)(uint8_t argc, uint8_t *argv)) {
70  callbackFunctions[command] = fn;
71 }
72 
73 /**
74  * @brief Read the command and args sent and execute the corresponding callback function,
75  * store the results of which in holding functions to be communicated with the host.
76  */
78  // UNPACK COMMAND/FUNCTION CODE & NUMBER OF ARGS (ARGC)
79  uint16_t CMD_ARGC = mb.Hreg(0);
80  int cmd = highByte(CMD_ARGC);
81  int argc = lowByte(CMD_ARGC);
82 
83  // Allocate space for argv to be transferred
84  uint8_t *argv = (uint8_t *)malloc(sizeof(uint8_t) * argc);
85 
86  // Read Hregs into argv
87  for(int i = 0; i < argc; i++) {
88  uint16_t thisWord = mb.Hreg(i/2 + 1); // read Hreg()
89 
90  // set argv[i] to the low or high byte of the current holding register depending the parity of the current index
91  argv[i] = (i % 2 == 0 ? highByte(thisWord) : lowByte(thisWord));
92  }
93 
94  // EXECUTE CALLBACK FUNCTION
95  struct registers result = (callbackFunctions[cmd])(argc, argv);
96 
97  // RESPOND WITH RESULT
98  for(int i = 0; i < result.count; i++) {
99  uint16_t thisWord = mb.Hreg(i/2 + 1); // Get the value of the current holding register
100  uint8_t curResult = result.value[i]; // Get the value of the current result
101 
102  // Write half the holding register at a time, depending on whether
103  // it will be the high or low byte (determined by the parity of i)
104  mb.Hreg(i/2 + 1, (i % 2 == 0 ? makeWord(curResult, 0) : thisWord | curResult));
105  }
106 
107  // Deallocate memory
108  free(argv);
109  if (result.value != nullptr) free(result.value);
110 
111  // Save the number of result values, return to idle command
112  mb.Hreg(0, result.count);
113 }
114 
115 /**
116  * Update modbus registers and check if a command has been received
117  * @remark Will return false unless there is a Command function code besides IDLE in Hreg 0
118  * _and_ there was data received since the last time mb.task() was called
119  * @return True or false
120  */
122  return mb.task() && (highByte(mb.Hreg(0)));
123 }
124 
struct registers pinMode(uint8_t argc, uint8_t *argv)
Change the settings of the Arduino I/O pins.
Definition: Functions.cpp:38
struct registers spiSettings(uint8_t argc, uint8_t *argv)
Change the settings of the SPI connection.
Definition: Functions.cpp:331
struct registers wireSetClock(uint8_t argc, uint8_t *argv)
Change the clock speed settings of the I2C connection.
Definition: Functions.cpp:239
struct registers wireRead(uint8_t argc, uint8_t *argv)
Read data from the connected I2C peripheral.
Definition: Functions.cpp:280
struct registers servoRead(uint8_t argc, uint8_t *argv)
Read a value from the connected servo.
Definition: Functions.cpp:194
struct registers wireWrite(uint8_t argc, uint8_t *argv)
Write data to the connected I2C peripheral.
Definition: Functions.cpp:256
struct registers wireEnd(uint8_t argc, uint8_t *argv)
End an I2C connection between the Arduino and a peripheral.
Definition: Functions.cpp:227
struct registers spiBegin(uint8_t argc, uint8_t *argv)
Begin a SPI connection between the Arduino and a peripheral.
Definition: Functions.cpp:313
struct registers analogWrite(uint8_t argc, uint8_t *argv)
Write an analog value (0-255) to the Arduino I/O pins.
Definition: Functions.cpp:88
struct registers servoWrite(uint8_t argc, uint8_t *argv)
Write a value to the connected servo.
Definition: Functions.cpp:170
struct registers servoDetach(uint8_t argc, uint8_t *argv)
Detach a servo from the the control interface.
Definition: Functions.cpp:147
struct registers servoAttach(uint8_t argc, uint8_t *argv)
Attach a connected servo to a control interface.
Definition: Functions.cpp:124
struct registers analogRead(uint8_t argc, uint8_t *argv)
Read an analog value (0-1023) from the Arduino I/O pins.
Definition: Functions.cpp:103
struct registers digitalRead(uint8_t argc, uint8_t *argv)
Read a digital value (HIGH/LOW) from the Arduino I/O pins.
Definition: Functions.cpp:68
struct registers spiTransferBuf(uint8_t argc, uint8_t *argv)
Exchange data over the SPI connection (Read + Write)
Definition: Functions.cpp:349
struct registers digitalWrite(uint8_t argc, uint8_t *argv)
Write a digital (HIGH/LOW) value to the Arduino I/O pins.
Definition: Functions.cpp:53
struct registers spiEnd(uint8_t argc, uint8_t *argv)
End a SPI connection between the Arduino and a peripheral.
Definition: Functions.cpp:381
struct registers wireBegin(uint8_t argc, uint8_t *argv)
Begin an I2C connection between the Arduino and a peripheral.
Definition: Functions.cpp:215
uint8_t * value
Definition: Functions.h:64
uint8_t count
Definition: Functions.h:61
A data structure to describe function arguments and return values.
Definition: Functions.h:59
Header file for 'Modmata.cpp'.
Base class for a host computer to control this (LattePanda's Arduino Leonardo) device.
Definition: Modmata.h:27
void attach(uint8_t command, struct registers(*fn)(uint8_t argc, uint8_t *argv))
Assign a function to a command number. Standard commands have default functions, but those can be ove...
Definition: Modmata.cpp:69
struct registers(* callbackFunctions[100])(uint8_t argc, uint8_t *argv)
An array of references to callback functions indexed by their function code number....
Definition: Modmata.h:38
ModbusSerial mb
Object representing an interactive Modbus connection over Serial.
Definition: Modmata.h:41
void processInput()
Read the command and args sent and execute the corresponding callback function, store the results of ...
Definition: Modmata.cpp:77
void begin(int baud)
Begin listening for a Modmata connection over serial/USB.
Definition: Modmata.cpp:31
Modmata namespace.
Definition: Modmata.h:24