Problem With code erroor

I am building mouse spaces from the guide and when I try to upload the code, it outputs an error Compilation error: a function-definition is not allowed here before '{' token
here is the code

void setup() {
  // put your setup code here, to run once:

}

void loop() {
    // This code is the combination of multiple works by others:
// 1. Original code for the Space Mushroom by Shiura on Thingiverse: https://www.thingiverse.com/thing:5739462
//    The next two from the comments on the instructables page: https://www.instructables.com/Space-Mushroom-Full-6-DOFs-Controller-for-CAD-Appl/
//    and the comments of Thingiverse: https://www.thingiverse.com/thing:5739462/comments
// 2. Code to emulate a 3DConnexion Space Mouse by jfedor: https://pastebin.com/gQxUrScV
// 3. This code was then remixed by BennyBWalker to include the above two sketches: https://pastebin.com/erhTgRBH
// 4. Four joystick remix code by fdmakara: https://www.thingiverse.com/thing:5817728
// The work by Teaching Tech involves mixing all of these. The basis is fdmakara's four joystick movement logic, with jfedor/BennyBWalker's HID SpaceMouse emulation.
// The four joystick logic sketch was setup for the joystick library instead of HID, so elements of this were omitted where not needed.
// The outputs were jumbled no matter how He plugged them in, so I spent a lot of time adding debugging code to track exactly what was happening.
// On top of this, He has added more control of speed/direction and comments/links to informative resources to try and explain what is happening in each phase.

// Spacemouse emulation
// Teaching Tech followed the instructions here from nebhead: https://gist.github.com/nebhead/c92da8f1a8b476f7c36c032a0ac2592a
// with two key differences:
// 1. He changed the word 'DaemonBite' to 'Spacemouse' in all references. 2. He changed the VID and PID values as per jfedor's instructions: vid=0x256f, pid=0xc631 (SpaceMouse Pro Wireless (cabled))
// When compiling and uploading, He select Arduino AVR boards (in Sketchbook) > Spacemouse and then the serial port.
// You will also need to download and install the 3DConnexion software: https://3dconnexion.com/us/drivers-application/3dxware-10/
// If all goes well, the 3DConnexion software will show a SpaceMouse Pro wireless when the Arduino is connected.
// *JC - John Crombie - I'd like to add a big thank you to Teaching Tech for this code. If it wasn't for this I wouldn't
// have been tempted to try to implement a Hall Effect sensor version. All my changes will be marked with a *JC comment
// All debug Serial.print statements have had the joystick output text has been renamed as HESx e.g. AX is now HSE0
/**********************************************
 * change log
 * C001 - 18-Jul-24 - Reversed default direction of Z rotation
 * C002 - 22-Jul-24 - Added state machine code to handle pressing two buttons at once to cause a third action and supress
 *                    suppress the default action of the two buttons pressed. Before I didn't supress the actions
 * C003 - 25-Jul-24 - Added define for movement3DC to switch between default 3DConnexion axis movement and Teaching Techs default movement
 * C004 - 04-Aug-24 - bug fix - Changed key reporting so that a zero report is sent when the final key is released.
 *                    Changed the place where duplicate keys reports are supressed. Used to be in the key rutine now in the report routine
 * C006 - 08-Aug-24 - bug fix - After logical button was pressed, all buttons were being sent in state 4. Now corrected.                   
 ************************************************/
 
// Include inbuilt Arduino HID library by NicoHood: https://github.com/NicoHood/HID 
#include "HID.h"

// Debugging
// 0: Debugging off. Set to this once everything is working.
// 1: *JC Output raw Hall Effect Sensor values. 176 - 862 raw ADC 10-bit values. 5V ADC reference
// 2: *JC Output centered Hall Effect Sensor values. Values should be approx -424 to +424, jitter around 0 at idle. ADC reference 2.56v
// 3: *JC Output centered Hall Effect Sensor values. Filtered for deadzone. Approx -424+DEADZONE to +424-DEADZONE, locked to zero at idle. Also button values. ADC reference 2.56v
// 4: Output translation and rotation values. Approx -500 to +500 depending on the parameter. *JC ADC reference 2.56v
// 5: Output debug 3 and 4 side by side for direct cause and effect reference. *JC ADC reference 2.56v
// 6: *JC Output debug info for pseudo key state machine. ( two keys pressed at once to simulate another key press)
int debug = 0;

// Choose between 3DConnexion default movement or Teaching Tech's
// With 3DConnexion you push the joystick away from you to zoom out and towards you to zoom in.
// lifting up the joystick moves up and pushing down moves down.
// With the Teaching Tech default, these two axis are swapped so that pulling up or pushing down the knob controls zoom
// and pushing away or pulling it towards you controls up and down. I prefer this.
// set to true for 3DConnection movement.
bool movement3DC  = false;

// Direction
// Modify the direction of translation/rotation depending on preference. This can also be done per application in the 3DConnexion software.
// Switch between true/false as desired.
bool invX = false; // pan left/right
bool invY = false; // Zoom in/out or pan up/down // C003 *JC - 3DC default movement or TT default
bool invZ = true; // pan up/down or zoom in/out // C003 *JC - 3DC default movement or TT default
bool invRX = false; // Rotate around X axis (tilt front/back)
bool invRY = false; // Rotate around Y axis (tilt left/right)
bool invRZ = false; // Rotate around Z axis (twist left/right)

// Speed
// Modify to change sensitibity/speed. Default and maximum 100. Works like a percentage ie. 50 is half as fast as default. This can also be done per application in the 3DConnexion software.
int16_t speed = 80;


// Default Assembly when looking from above: *JC modified for Hall Effect Sensors (HES)
//      7 6          Y+
//       |           .
// 8 9 --+--2 3 X-...Z+...X+
//       |           .
//      0 1          Y-
//
// Wiring. Matches the first eight analogue pins of the Arduino Pro Micro (atmega32u4)
int PINLIST[8] = { // The positions of the reads *JC comments indicate which Hall Effect sensor is connected
  A0, // HES 6 o'clock left
  A1, // HES 6 o'clock right
  A2, // HES 3 o'clock near
  A3, // HES 3 o'clock far
  A6, // HES 12 o'clock right
  A7, // HES 12 o'clock left
  A8, // HES 9 o'clock far
  A9  // HES 9 o'clock near
};

// *JC added button list for digital inputs
int BTNLIST[3] = { // Button pin list
  0,
  1,
  2
};

// Deadzone to filter out unintended movements. 
// Increase if the mouse has small movements when it should be idle or the mouse is too senstive to subtle movements.
// Note that the 3d Connections also has its own deadzone processes
int DEADZONE = 40;


// This portion sets up the communication with the 3DConnexion software. The communication protocol is created here.
// hidReportDescriptor webpage can be found here: https://eleccelerator.com/tutorial-about-usb-hid-report-descriptors/ 
static const uint8_t _hidReportDescriptor[] PROGMEM = {
  0x05, 0x01,           //  Usage Page (Generic Desktop)
  0x09, 0x08,           //  0x08: Usage (Multi-Axis)
  0xa1, 0x01,           //  Collection (Application)
  0xa1, 0x00,           // Collection (Physical)
  0x85, 0x01,           //  Report ID
  0x16, 0x00, 0x80,     //logical minimum (-500)
  0x26, 0xff, 0x7f,     //logical maximum (500)
  0x36, 0x00, 0x80,     //Physical Minimum (-32768)
  0x46, 0xff, 0x7f,     //Physical Maximum (32767)
  0x09, 0x30,           //    Usage (X)
  0x09, 0x31,           //    Usage (Y)
  0x09, 0x32,           //    Usage (Z)
  0x75, 0x10,           //    Report Size (16)
  0x95, 0x03,           //    Report Count (3)
  0x81, 0x02,           //    Input (variable,absolute)
  0xC0,                 //  End Collection
  0xa1, 0x00,           // Collection (Physical)
  0x85, 0x02,           //  Report ID
  0x16, 0x00, 0x80,     //logical minimum (-500)
  0x26, 0xff, 0x7f,     //logical maximum (500)
  0x36, 0x00, 0x80,     //Physical Minimum (-32768)
  0x46, 0xff, 0x7f,     //Physical Maximum (32767)
  0x09, 0x33,           //    Usage (RX)
  0x09, 0x34,           //    Usage (RY)
  0x09, 0x35,           //    Usage (RZ)
  0x75, 0x10,           //    Report Size (16)
  0x95, 0x03,           //    Report Count (3)
  0x81, 0x02,           //    Input (variable,absolute)
  0xC0,                 //  End Collection
 
  0xa1, 0x00,           // Collection (Physical)
  0x85, 0x03,           //  Report ID
  0x15, 0x00,           //   Logical Minimum (0)
  0x25, 0x01,           //    Logical Maximum (1)
  0x75, 0x01,           //    Report Size (1)
  0x95, 32,             //    Report Count (24) // *JC - I dont undwerstand what the comment says 24 but gives a value of 32
  0x05, 0x09,           //    Usage Page (Button)
  0x19, 1,              //    Usage Minimum (Button #1)
  0x29, 32,             //    Usage Maximum (Button #24) // *JC - same comment as above
  0x81, 0x02,           //    Input (variable,absolute)
  0xC0,
  0xC0
};

// Sensors are matched to pin order.
// *JC - Note HES0 and BTN0 are not the same pin. HSE0 is Analog input 0 and BTN0 is digital input 0
#define HES0 0
#define HES1 1
#define HES2 2
#define HES3 3
#define HES6 4
#define HES7 5
#define HES8 6
#define HES9 7
#define BTN0 0
#define BTN1 1
#define BTN2 2

// Centerpoint variable to be populated during setup routine.
int centerPoints[8];

// Function to read and store analogue voltages for each joystick axis.
void readAllFromSensors(int *rawReads){
  for(int i=0; i<8; i++){
    rawReads[i] = analogRead(PINLIST[i]);
  }
}

// *JC Function to read and store button values
// When pressing two buttons at once for a different function, one button is usually pressed slightly before the other.
// To prevent the first buttons function being triggered, we wait 15ms to see if another button is pressed in the meantime.
// if so we send the pseudo button value. if not we send the first button value.
// keyState 0 - no button pressed
// keyState 1 - 1 or 3 pressed
// keystate 2 - 1&3 pressed within time limit
// keystate 3 = 1&3 not pressed within time limit
// keyState 4 = Wait until physical buttons released to reset state.
unsigned long keyTimeNew, keyTimeOld = 0;
uint8_t keyState = 0, keyPressed = 0, oldButtonValues[4] = {0,0,0,0}; // C004 - *JC - keyPresed added to keep track of last key pressed (in state machine).

void readAllFromButtons(uint8_t *buttonValues){
  for(int i=1; i<4; i++){ // read real button values
    buttonValues[i] = !digitalRead(BTNLIST[i-1]);
  }

  // C002 - *JC changed logic for handling pseudo/logical switch (two buttons pressed at once gives different function)
  buttonValues[0] = false;
  keyTimeNew = millis();
  switch(keyState) {
    case 0: // no button pressed so far
     if (buttonValues[1] || buttonValues[3]) {
       if (debug == 6) Serial.println("keyState 0 - button pressed move to keyState 1");
       keyState = 1;
       keyTimeOld = keyTimeNew;
       buttonValues[1] = buttonValues[3] = false; // don't send button values yet.
     }
     break;

     case 1: // button 1 or 3 pressed - what has happened with the elapsed time
     if (debug == 6) Serial.println("keyState 1 - one button pressed");
     if (keyTimeNew - keyTimeOld > 15) {
       keyState = 3; // second button not pressed
     } else if (buttonValues[1] && buttonValues[3]) {
       keyState = 2; // second button pressed
     }
     buttonValues[1] = buttonValues[3] = false; // don't send button values yet
     break;

     case 2: // second button pressed - set logical button
     if (debug == 6) Serial.println("keyState 2 - second button pressed - set logical button");
     buttonValues[0] = true;
     keyState = 4;
     keyPressed = 0; // C004 - *JC - record button 0 pressed
     buttonValues[1] = buttonValues[3] = false;
     break;

     case 3: // second button not pressed, send the original button
     if (debug == 6) Serial.println("keyState 3 - second button not pressed in time");
     keyState = 4;
     if (buttonValues[1]) { // C004 - *JC - record which button was pressed and will be reported
      keyPressed = 1;
     } else {
      keyPressed = 3;
     }
     break;

     case 4: //wait until buttons released to reset state
     if (debug == 6) Serial.println("keyState 4 - wait for buttons to be released before resetting state");

     if (!buttonValues[1] && !buttonValues[3]) {
       keyState = 0;   
     }
     buttonValues[0] = buttonValues[1] = buttonValues[3] = false; //C005 - *JC - bug fix. Was here before but was removed for the last release
     buttonValues[keyPressed] = true; // C004 - *JC - keep the keys pressed.

     break;
}

      
/* C004 - *JC - move supression of sending multiple key reports to report sending routine. 
// *JC - only send button value once 
  for (int i=0;i<4;i++) {
    if (buttonValues[i] == oldButtonValues[i]) {
      buttonValues[i]=0; // send only once
    } else {
      if (debug == 6) {
        Serial.print("Button "); Serial.print(i); Serial.print(" changed - Old Value ");Serial.print(oldButtonValues[i]); Serial.print(" New Value ");Serial.println(buttonValues[i]);
      }
      oldButtonValues[i] = buttonValues[i];   
    }
   }
*/
  //  based on real values set logical switch
  /*  Old code to handle logical button - doesn't supress first button pressed action
  if( buttonValues[1] && buttonValues[3]) {
    buttonValues[0] = true;
    buttonValues[1] = buttonValues[3] = false;
  }
  else
  {
    buttonValues[0] = false;
  }
  */
}

void setup() {
  // HID protocol is set.
  static HIDSubDescriptor node(_hidReportDescriptor, sizeof(_hidReportDescriptor));
  HID().AppendDescriptor(&node);
  // Begin Seral for debugging
  Serial.begin(250000);
  delay(100);
  // *JC - setup button pins for digitalRead
  for(int i=0; i<3; i++){
    pinMode(BTNLIST[i],INPUT_PULLUP);
  }
  //*JC - reduce ADC reference voltage from 5V to 2.56 if not using debug = 1
  if (debug == 1) {
    analogReference(DEFAULT);
  } else {
    analogReference(INTERNAL);
  }

  // Read idle/centre positions for Sensors.
  // *JC - First read gives unpredictable values so do it twice
  readAllFromSensors(centerPoints);
  readAllFromSensors(centerPoints);
}

uint8_t keyChange = 0; // C004 - *JC - variable to determine if new key report needs to be sent.
// Function to send translation and rotation data to the 3DConnexion software using the HID protocol outlined earlier. Two sets of data are sent: translation and then rotation.
// For each, a 16bit integer is split into two using bit shifting. The first is mangitude and the second is direction.
// *JC - Added button report
void send_command(int16_t rx, int16_t ry, int16_t rz, int16_t x, int16_t y, int16_t z, uint8_t *buttonValues) {
  uint8_t trans[6] = { x & 0xFF, x >> 8, y & 0xFF, y >> 8, z & 0xFF, z >> 8 };
  HID().SendReport(1, trans, 6);
  uint8_t rot[6] = { rx & 0xFF, rx >> 8, ry & 0xFF, ry >> 8, rz & 0xFF, rz >> 8 };
  HID().SendReport(2, rot, 6);
  // *JC - Button Report
  // these are the button functions for first byte in Fusion 360. For other functions see the GitHub repositry
  //  bit 0 - bring up configuration dialog - logical button (press BTN0 and BTN2 at the same time) rotaee 45 degrees
  //  bit 1 - fit to screen
  //  bit 2 - plan view
  //  bit 3 - no function?
  //  bit 4 - right view hide
  //  bit 5 - front view File
  //  bit 6 - no function?
  //  bit 7 - no function?
  uint8_t btn[4] ={32*buttonValues[3]+16*buttonValues[2]+4*buttonValues[1]+buttonValues[0],0,0,0};
  if (buttonValues[0]+2*buttonValues[1]+4*buttonValues[2]+8*buttonValues[3]!=keyChange) { // C004 - *JC - changed operation *JC - only send report if a button is pressed
    HID().SendReport(3,btn,4);
    keyChange = buttonValues[0]+2*buttonValues[1]+4*buttonValues[2]+8*buttonValues[3]; // C004 - *JC - record keys pressed for next time through the loop
    if (debug == 6) {Serial.print("keyChange = "); Serial.println(keyChange);} // C005 - *JC - to help debug key press issues

  }
}

void loop() {
  int rawReads[8], centered[8];
  uint8_t buttonReads[4];
  // sensor values are read. range should be 176 - 1024 for debug levels other than 1 and 88-860 for debug 1
  readAllFromSensors(rawReads);
  // button values true or false
  readAllFromButtons(buttonReads);
  // Report back 0-1023 raw ADC 10-bit values if enabled
  if(debug == 1){ 
    Serial.print("HES0:"); Serial.print(rawReads[0]); Serial.print(",");
    Serial.print("HES1:"); Serial.print(rawReads[1]); Serial.print(",");
    Serial.print("HES2:"); Serial.print(rawReads[2]); Serial.print(",");
    Serial.print("HES3:"); Serial.print(rawReads[3]); Serial.print(",");
    Serial.print("HES6:"); Serial.print(rawReads[4]); Serial.print(",");
    Serial.print("HES7:"); Serial.print(rawReads[5]); Serial.print(",");
    Serial.print("HES8:"); Serial.print(rawReads[6]); Serial.print(",");
    Serial.print("HES9:"); Serial.println(rawReads[7]);
  }

  // Subtract centre position from measured position to determine movement.
  // *JC - As we are going negative with the readings, we make them positive
  // by subtraction them from the recorded centerPoints rather than the other was around.
  // C0004 - changed back to the original TT version to match the code from AndunHH 
  for(int i=0; i<8; i++) centered[i] = centerPoints[i]-rawReads[i]; // 
  // Report centered Sensor values if enabled. Values should be approx -256 to +256, jitter around 0 at idle.
  if(debug == 2){
    Serial.print("HES0:"); Serial.print(centered[0]); Serial.print(",");
    Serial.print("HES1:"); Serial.print(centered[1]); Serial.print(",");
    Serial.print("HES2:"); Serial.print(centered[2]); Serial.print(",");
    Serial.print("HES3:"); Serial.print(centered[3]); Serial.print(",");
    Serial.print("HES6:"); Serial.print(centered[4]); Serial.print(",");
    Serial.print("HES7:"); Serial.print(centered[5]); Serial.print(",");
    Serial.print("HES8:"); Serial.print(centered[6]); Serial.print(",");
    Serial.print("HES9:"); Serial.println(centered[7]);
  }
  // Filter movement values. Set to zero if movement is below deadzone threshold.
  // *JC - Changed operation so there isn't a sudden jump when the value first falls outside deadzone
  for(int i=0; i<8; i++){
    if(centered[i]<DEADZONE && centered[i]>-DEADZONE) {
      centered[i] = 0;
    } else {
      int sgn = centered[i] / abs(centered[i]);
      centered[i] = sgn*(abs(centered[i])-DEADZONE);
    }
  }
  // Report centered Sensor values. Filtered for deadzone. Approx -500 to +500, locked to zero at idle
  if(debug == 3){
    Serial.print("HES0:"); Serial.print(centered[0]); Serial.print(",");
    Serial.print("HES1:"); Serial.print(centered[1]); Serial.print(",");
    Serial.print("HES2:"); Serial.print(centered[2]); Serial.print(",");
    Serial.print("HES3:"); Serial.print(centered[3]); Serial.print(",");
    Serial.print("HES6:"); Serial.print(centered[4]); Serial.print(",");
    Serial.print("HES7:"); Serial.print(centered[5]); Serial.print(",");
    Serial.print("HES8:"); Serial.print(centered[6]); Serial.print(",");
    Serial.print("HES9:"); Serial.print(centered[7]); Serial.print(",");
    Serial.print("But0:"); Serial.print(buttonReads[0]); Serial.print(",");
    Serial.print("But1:"); Serial.print(buttonReads[1]); Serial.print(",");
    Serial.print("But2:"); Serial.print(buttonReads[2]); Serial.print(",");
    Serial.print("But3:"); Serial.println(buttonReads[3]);  
  }

  // Doing all through arithmetic contribution by fdmakara
  // Integer has been changed to 16 bit int16_t to match what the HID protocol expects.
  int16_t transX, transY, transZ, rotX, rotY, rotZ; // Declare movement variables at 16 bit integers
  // Original fdmakara calculations
  //transX = (-centered[AX] +centered[CX])/1;
  //transY = (-centered[BX] +centered[DX])/1;
  //transZ = (-centered[AY] -centered[BY] -centered[CY] -centered[DY])/2;
  //rotX = (-centered[AY] +centered[CY])/2;
  //rotY = (+centered[BY] -centered[DY])/2;
  //rotZ = (+centered[AX] +centered[BX] +centered[CX] +centered[DX])/4;
  
  // *JC - Replaced Joystick calculations with ones for the Hall Effect Sensors
  transX = (centered[HES1]-centered[HES0]+centered[HES6]-centered[HES7])/2;  
  transY = (centered[HES2]-centered[HES3]+centered[HES9]-centered[HES8])/2;  
  transZ = (centered[HES0]+centered[HES1]+centered[HES2]+centered[HES3]+centered[HES6]+centered[HES7]+centered[HES8]+centered[HES9])/4;
  rotX = (centered[HES0]+centered[HES1]-centered[HES6]-centered[HES7])/2;
  rotY = (centered[HES8]+centered[HES9]-centered[HES2]-centered[HES3])/2;
  rotZ = (centered[HES0]+centered[HES2]+centered[HES6]+centered[HES8]-centered[HES1]-centered[HES3]-centered[HES7]-centered[HES9])/4; // C0001 *JC - changed default direction of rotation
// *JC - modified speed calculation to allow for the fact that this is integer calculations
// so do multiplications prior to divisions to maintain maximum accuracy.
  transX = (transX*speed)/100;
  transY = (transY*speed)/100;
  transZ = (transZ*speed)/100;
  rotX = (rotX*speed)/100;
  rotY = (rotY*speed)/100;
  rotZ = (rotZ*speed)/100;
// Invert directions if needed
  if(invX == true){ transX = transX*-1;};
  if(invY == true){ transY = transY*-1;};
  if(invZ == true){ transZ = transZ*-1;};
  if(invRX == true){ rotX = rotX*-1;};
  if(invRY == true){ rotY = rotY*-1;};
  if(invRZ == true){ rotZ = rotZ*-1;};

// Report translation and rotation values if enabled. Approx -800 to 800 depending on the parameter.
  if(debug == 4){
    Serial.print("TX:"); Serial.print(transX); Serial.print(",");
    Serial.print("TY:"); Serial.print(transY); Serial.print(",");
    Serial.print("TZ:"); Serial.print(transZ); Serial.print(",");
    Serial.print("RX:"); Serial.print(rotX); Serial.print(",");
    Serial.print("RY:"); Serial.print(rotY); Serial.print(",");
    Serial.print("RZ:"); Serial.println(rotZ);
  }
// Report debug 4 and 5 info side by side for direct reference if enabled. Very useful if you need to alter which inputs are used in th arithmatic above.
  if(debug == 5){
    Serial.print("HES0:"); Serial.print(centered[0]); Serial.print(",");
    Serial.print("HES1:"); Serial.print(centered[1]); Serial.print(",");
    Serial.print("HES2:"); Serial.print(centered[2]); Serial.print(",");
    Serial.print("HES3:"); Serial.print(centered[3]); Serial.print(",");
    Serial.print("HES6:"); Serial.print(centered[4]); Serial.print(",");
    Serial.print("HES7:"); Serial.print(centered[5]); Serial.print(",");
    Serial.print("HES8:"); Serial.print(centered[6]); Serial.print(",");
    Serial.print("HES9:"); Serial.print(centered[7]); Serial.print("||");
    Serial.print("TX:"); Serial.print(transX); Serial.print(",");
    Serial.print("TY:"); Serial.print(transY); Serial.print(",");
    Serial.print("TZ:"); Serial.print(transZ); Serial.print(",");
    Serial.print("RX:"); Serial.print(rotX); Serial.print(",");
    Serial.print("RY:"); Serial.print(rotY); Serial.print(",");
    Serial.print("RZ:"); Serial.println(rotZ);
  }

// Send data to the 3DConnexion software.
// The correct order for me was determined after trial and error - Teaching Tech
// *JC - Added buttons for button report
// *JC C003 Allowing swap between TT movement and 3DC movement defaults.
  if (movement3DC) {
    send_command(rotX, rotY, rotZ, transX, transY, transZ,buttonReads); // 3DC default
  }
  else {
    send_command(rotX, rotY, rotZ, transX, transZ, transY,buttonReads); // TT default
  }
}

}

Post the error log in code tags

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.