--- /dev/null
+#!/usr/bin/python3
+
+import tkinter as tk
+from tkinter import ttk
+import serial
+import threading
+from pprint import pprint
+import queue
+import re
+from tkinter import filedialog
+
+
+# Configuration
+PORT = '/dev/Xmatter_SMC'
+BAUD_RATE = 9600
+input_queue = queue.Queue()
+stop_event = threading.Event()
+
+STEP_SIZE = 0.3125
+CORRECTION_X = 1.001
+CORRECTION_Y = 1.001
+
+def twos_complement(hexstr, bits):
+ value = int(hexstr, 16)
+ if value & (1 << (bits - 1)):
+ value -= 1 << bits
+ return value
+
+
+class SerialGUI:
+ def __init__(self, root):
+ self.root = root
+ self.root.title("Step Motor Controller")
+ self.root.columnconfigure(1, weight=1)
+ self.root.columnconfigure(2, weight=1)
+
+ labels = [
+ "Position [steps]", "Position [um]", "Goto [steps]", "Goto [um]",
+ "Move by [steps]", "Move by [um]", "Stepsize", "Speed"]
+ names = ["PS","PU","GS","GU","MS","MU","SS","SP"]
+ self.entries = {}
+
+ for row, label_text in enumerate(labels):
+ label = ttk.Label(root, text=label_text)
+ label.grid(row=row, column=0, padx=8, pady=5, sticky="w")
+
+ entry1 = ttk.Entry(root)
+ entry1.grid(row=row, column=1, padx=5, pady=5, sticky="ew")
+
+ if row < 6:
+ entry2 = ttk.Entry(root)
+ entry2.grid(row=row, column=2, padx=5, pady=5, sticky="ew")
+
+ if row < 6:
+ self.entries[names[row]+"X"] = entry1
+ self.entries[names[row]+"Y"] = entry2
+ else:
+ self.entries[names[row]] = entry1
+
+ colors = ["red", "green", "green", "green", "green"]
+ colname = ["Active","X+","X-","Y+","Y-"];
+ color_frame = tk.Frame(root)
+ color_frame.grid(
+ row=8, column=0, columnspan=3,
+ padx=8, pady=12, sticky="ew"
+ )
+
+ for col, color in enumerate(colors):
+ rectangle = tk.Canvas(
+ color_frame,
+ width=80,
+ height=30,
+ bg=color,
+ highlightthickness=0,
+ )
+ rectangle.create_text(
+ 40, 15, # Center of 80 x 30 rectangle
+ text=colname[col],
+ fill="black", # Text color
+ font=("Arial", 10, "bold"),
+ )
+ rectangle.grid(row=0, column=col, padx=5)
+ self.entries[colname[col]] = rectangle
+
+ ttk.Button(
+ root,
+ text="Store",
+ style="Tiny.TButton",
+ command=lambda: self.storeposition()
+ ).grid(row=9, column=0)
+ ttk.Button(
+ root,
+ text="Save",
+ style="Tiny.TButton",
+ command=lambda: self.savelog()
+
+ ).grid(row=10, column=0)
+
+ text_box = tk.Text(
+ root,
+ height=10,
+ width=50,
+ wrap="word", # Wrap long lines
+ font=("Courier", 11)
+ )
+ text_box.grid(row=9, column=1, columnspan=2, rowspan=2)
+ self.entries["store"] = text_box
+
+ label = ttk.Label(root, text="Raw Input")
+ label.grid(row=11, column=0, padx=8, pady=5, sticky="w")
+ entry1 = ttk.Entry(root)
+ entry1.grid(row=11, column=1, columnspan=2, padx=5, pady=5, sticky="ew")
+
+ self.entries["raw"] = entry1
+ # --- Serial Setup ---
+ try:
+ self.ser = serial.Serial(PORT, BAUD_RATE, timeout=1)
+ except Exception as e:
+ self.display_var.set(f"Error: Could not open {PORT}\n{e}")
+ return
+
+ # Start a background thread to read serial data without freezing the GUI
+ self.thread = threading.Thread(target=self.read_serial, daemon=True)
+ self.thread.start()
+
+ def storeposition(self):
+ xs = self.entries["PSX"].get()
+ xu = self.entries["PUX"].get()
+ ys = self.entries["PSY"].get()
+ yu = self.entries["PUY"].get()
+ self.entries["store"].insert("end",f"{xs} {ys}\t{xu} {yu}\n")
+
+ def savelog(self):
+ filename = filedialog.asksaveasfilename(
+ title="Save text",
+ defaultextension=".txt",
+ filetypes=[("Text files", "*.txt"), ("All files", "*.*")]
+ )
+ if filename:
+ with open(filename, "w", encoding="utf-8") as file:
+ file.write(self.entries["store"].get("1.0", "end-1c"))
+
+
+ def setbox(self, name, value, digits=4):
+ # if value is (int, float):
+ try:
+ if not value.is_integer():
+ value = str(round(float(value),digits))
+ except:
+ pass
+ # value = value
+ self.entries[name].delete(0, tk.END)
+ self.entries[name].insert(0,value)
+
+ def update_display(self):
+ inputline = None
+ while True:
+ try:
+ inputline = input_queue.get_nowait()
+ except queue.Empty:
+ break
+ if inputline is not None:
+ # print(inputline)
+ self.setbox("raw",inputline)
+ m = re.search(r"P([0-9a-fA-F]+),([0-9a-fA-F]+)",inputline)
+ if m:
+ xs = twos_complement(m.group(1),32)
+ ys = twos_complement(m.group(2),32)
+ self.setbox("PSX",xs)
+ self.setbox("PSY",ys)
+ self.setbox("PUX",xs * STEP_SIZE * CORRECTION_X, 2)
+ self.setbox("PUY",ys * STEP_SIZE * CORRECTION_Y, 2)
+ m = re.search(r"S([01])([01])([01])([01])([01])",inputline)
+ if m:
+ if m.group(1) == '1':
+ self.entries["X-"].configure(bg="red")
+ else:
+ self.entries["X-"].configure(bg="green")
+ if m.group(2) == '1':
+ self.entries["X+"].configure(bg="red")
+ else:
+ self.entries["X+"].configure(bg="green")
+ if m.group(3) == '1':
+ self.entries["Y-"].configure(bg="red")
+ else:
+ self.entries["Y-"].configure(bg="green")
+ if m.group(4) == '1':
+ self.entries["Y+"].configure(bg="red")
+ else:
+ self.entries["Y+"].configure(bg="green")
+ if m.group(5) == '1':
+ self.entries["Active"].configure(bg="green")
+ else:
+ self.entries["Active"].configure(bg="red")
+
+
+ if not stop_event.is_set():
+ root.after(50, self.update_display)
+
+
+ def read_serial(self):
+ while not stop_event.is_set():
+ while self.ser.in_waiting > 0:
+ try:
+ # Read line and decode bytes to string
+ line = self.ser.readline().decode('utf-8').strip("\r\n").replace("\0","").replace(" ","")
+ if line:
+ # Update the UI from the thread safely
+ input_queue.put(line)
+ except Exception:
+ pass
+
+ # def send_data(self):
+ # data = self.entry.get()
+ # if data:
+ # try:
+ # # Add newline character and send as bytes
+ # self.ser.write((data + '\n').encode('utf-8'))
+ # self.entry.delete(0, tk.END) # Clear input field
+ # except Exception as e:
+ # print(f"Send Error: {e}")
+def close_window():
+ stop_event.set()
+ root.destroy()
+
+if __name__ == "__main__":
+ root = tk.Tk()
+ root.protocol("WM_DELETE_WINDOW", close_window)
+ app = SerialGUI(root)
+ root.after(50, SerialGUI.update_display(app))
+ root.mainloop()
+
// #include <avr/eeprom.h>
#include "lcdlib/font.h"
#include "lcdlib/lcd-color-graphic.h"
-#include "twi.h"
+// #include "twi.h"
#include <avr/interrupt.h>
#include <avr/io.h>
#include <string.h>
#include <usb_serial.h>
#include <util/delay.h>
+#include <stdio.h>
void getdata(uint8_t buf);
uint8_t rxcnt = 0, txpoint = 0;
uint8_t rxbuf[15];
uint8_t txbuf[15];
+uint8_t buffer[24];
color_t colors[16];
color_t topback;
volatile uint8_t keypad[16] = { 0 };
return value;
}
-void send_answer_buf(uint8_t* b) { UCSR1B |= (1 << UDRIE1); }
+// void send_answer_buf(uint8_t* b) { UCSR1B |= (1 << UDRIE1); }
// activate transmit interupt "ISR(USART1_UDRE_vect)"
+
+
+void send_string(uint8_t* buf, uint8_t len)
+{
+ usb_serial_write(buf, len);
+ usb_serial_flush_output();
+}
+
// compose response string
void send_answer_hex(uint8_t* rxbuf, uint32_t v)
{
txbuf[10] = nib_to_hex(v, 0);
txbuf[11] = '\n';
txbuf[12] = 0;
- usb_serial_write(txbuf, 12);
- usb_serial_flush_output();
+ send_string(txbuf,12);
+ // usb_serial_write(txbuf, 12);
+ // usb_serial_flush_output();
// send_answer_buf(txbuf);
}
+
// R0100000000
/*****************************************************************
* Setting functions
{
}
+
+void updateSpeed(uint8_t speed) {
+ cli();
+ OCR1A = speeds[speed];
+ TCNT1 = 0;
+ sei();
+ lcd_set_font(FONT_PROP_16, SPACING);
+ lcd_set_area_xy(280, 320, 48, 64);
+ LCD_MOVE_TO(48, 280);
+ lcd_putstr_P(PSTR("Sp "));
+ lcd_put_short(speed);
+}
+
+void updateStepsize(void) {
+ lcd_set_font(FONT_DIGITS_32, SPACING);
+ LCD_MOVE_TO(200, 16);
+ lcd_set_area_xy(16, 240, 200, 232);
+ lcd_put_long_align32_7(stepsize);
+ lcd_set_font(FONT_PROP_16, SPACING);
+}
+
+void MoveAbsoluteX(int32_t pos) {
+ cli();
+ M1_STEPS = 0;
+ if (M1_position < pos) {
+ DIRECTION_FORWARD_M1();
+ M1_DIR = 1;
+ M1_STEPS = pos - M1_position;
+ } else {
+ DIRECTION_BACKWARD_M1();
+ M1_DIR = 0;
+ M1_STEPS = M1_position - pos;
+ }
+ sei();
+}
+
+void MoveAbsoluteY(int32_t pos) {
+ cli();
+ M2_STEPS = 0;
+ if (M2_position < pos) {
+ DIRECTION_FORWARD_M2();
+ M2_DIR = 1;
+ M2_STEPS = pos - M2_position;
+ } else {
+ DIRECTION_BACKWARD_M2();
+ M2_DIR = 0;
+ M2_STEPS = M2_position - pos;
+ }
+ sei();
+}
/*****************************************************************
* Communication
*****************************************************************/
if (regnumber == 1) { // Register 1: PIN
send_answer_hex(&rxbuf[0], 0xabcd1234);
}
+ if (regnumber == 2) { // Register 2: Switches (0,0,speed,act,yh,yl,xh,xl)
+ send_answer_hex(&rxbuf[0], M1_SWITCH_LOW + (M1_SWITCH_HIGH<<4) + (M2_SWITCH_LOW << 8) + (M2_SWITCH_HIGH << 12) + ((uint32_t)motor_active << 16));
+ }
+ if (regnumber == 3) { // Register 3: Step size
+ send_answer_hex(&rxbuf[0], stepsize);
+ }
+ if (regnumber == 4) { // Register 4: Speed
+ send_answer_hex(&rxbuf[0], speed);
+ }
+ if (regnumber == 5) { // Register 5: Position X
+ send_answer_hex(&rxbuf[0], M1_position);
+ }
+ if (regnumber == 6) { // Register 6: Position Y
+ send_answer_hex(&rxbuf[0], M2_position);
+ }
+
}
if (rxbuf[0] == 'W') {
uint32_t value = hex_to_int32(&rxbuf[3]);
if (regnumber == 0) {
send_answer_hex(&rxbuf[0], value);
}
+ if (regnumber == 3) { // Register 3: Stepsize W0300000190
+ stepsize = hex_to_int32(&rxbuf[3]);
+ updateStepsize();
+ send_answer_hex(&rxbuf[0], stepsize);
+ }
+
+ if (regnumber == 4) { // Register 4: Speed W0400000007
+ speed = hex_to_int(rxbuf[10]) & 0x7;
+ updateSpeed( speed );
+ send_answer_hex(&rxbuf[0], speed);
+ }
+ if (regnumber == 5) { // Register 5: Move Absolute X W0500007895
+ int32_t pos = hex_to_int32(&rxbuf[3]);
+ MoveAbsoluteX(pos);
+ send_answer_hex(&rxbuf[0], pos);
+ }
+ if (regnumber == 6) { // Register 6: Move Absolute Y W06FFFF7895
+ int32_t pos = hex_to_int32(&rxbuf[3]);
+ MoveAbsoluteY(pos);
+ send_answer_hex(&rxbuf[0], pos);
+ }
+
}
}
}
rxcnt = 0;
}
}
-
+// R0200000000
+// R0300000000
// R0000000000
/*****************************************************************
* Main function
lcd_use_foreground(colors[0]);
lcd_putstr_xy_P(PSTR("<-->"), 32, 280);
lcd_putstr_xy_P(PSTR("Sp 4"), 48, 280);
- lcd_set_font(FONT_DIGITS_32, SPACING);
- LCD_MOVE_TO(200, 46);
- lcd_put_long(stepsize);
- lcd_set_font(FONT_PROP_16, SPACING);
-
+ updateStepsize();
uint16_t lasttime = 0;
for (uint8_t i = 0; i < 16; i++)
}
if (keypad[5]) { // 5, toggle single step mode
cli();
- if(stepsize != 1) {
- stored_stepsize = stepsize;
- stepsize = 1;
- }
- else {
- stepsize = stored_stepsize;
- }
+ if (stepsize != 1) {
+ stored_stepsize = stepsize;
+ stepsize = 1;
+ } else {
+ stepsize = stored_stepsize;
+ }
sei();
+ updateStepsize();
- lcd_set_font(FONT_DIGITS_32, SPACING);
- LCD_MOVE_TO(200, 16);
- lcd_set_area_xy(16, 240, 200, 232);
- lcd_put_long_align32_7(stepsize);
- lcd_set_font(FONT_PROP_16, SPACING);
-
keypad[5] = 255;
}
if (keypad[6]) { // 8
if (stepsize > 100000)
stepsize = 100000;
keypad[11] = 255;
- lcd_set_font(FONT_DIGITS_32, SPACING);
- LCD_MOVE_TO(200, 16);
- lcd_set_area_xy(16, 240, 200, 232);
- lcd_put_long_align32_7(stepsize);
- lcd_set_font(FONT_PROP_16, SPACING);
+ updateStepsize();
}
if (keypad[3] && keypad[3] != 255) { // *
speed = inputbuffer & 0x7;
inputbuffer = 0;
negativeinput = 0;
- cli();
- OCR1A = speeds[speed];
- TCNT1 = 0;
- sei();
keypad[3] = 255;
- lcd_set_font(FONT_PROP_16, SPACING);
- lcd_set_area_xy(280, 320, 48, 64);
- LCD_MOVE_TO(48, 280);
- lcd_putstr_P(PSTR("Sp "));
- lcd_put_short(speed);
+ updateSpeed(speed);
}
if (keypad[14] && keypad[14] != 255) { // C
if (motor_active) {
- cli();
- M1_STEPS = 0;
if (negativeinput)
inputbuffer *= -1;
- if (M1_position < inputbuffer) {
- DIRECTION_FORWARD_M1();
- M1_DIR = 1;
- M1_STEPS = inputbuffer - M1_position;
- } else {
- DIRECTION_BACKWARD_M1();
- M1_DIR = 0;
- M1_STEPS = M1_position - inputbuffer;
- }
+ MoveAbsoluteX(inputbuffer);
inputbuffer = 0;
negativeinput = 0;
- sei();
}
keypad[14] = 255;
}
if (keypad[15] && keypad[15] != 255) { // D
if (motor_active) {
- cli();
- M2_STEPS = 0;
if (negativeinput)
inputbuffer *= -1;
- if (M2_position < inputbuffer) {
- DIRECTION_FORWARD_M2();
- M2_DIR = 1;
- M2_STEPS = inputbuffer - M2_position;
- } else {
- DIRECTION_BACKWARD_M2();
- M2_DIR = 0;
- M2_STEPS = M2_position - inputbuffer;
- }
+ MoveAbsoluteY(inputbuffer);
inputbuffer = 0;
negativeinput = 0;
- sei();
}
+
keypad[15] = 255;
}
if (inputbuffer > 1000000)
lcd_set_font(FONT_PROP_16, SPACING);
LCD_MOVE_TO(24, 0);
+ // }
+ //output position to USB
+ // if ((time & 0x7) == 0) {
+ strncpy((char*)buffer, " ", 24);
+ buffer[0]='P';
+ ltoa(M1_position, (char*)buffer+1, 16);
+ buffer[11]=',';
+ ltoa(M2_position, (char*)buffer+12, 16);
+ buffer[22]='\n';
+ buffer[23] = 0;
+ send_string(buffer,24);
+
+ strncpy((char*)buffer, " ", 24);
+ buffer[0]='S';
+ buffer[1]=M1_SWITCH_LOW?'1':'0';
+ buffer[2]=M1_SWITCH_HIGH?'1':'0';
+ buffer[3]=M2_SWITCH_LOW?'1':'0';
+ buffer[4]=M2_SWITCH_HIGH?'1':'0';
+ buffer[5]=motor_active?'1':'0';
+ buffer[6]='\n';
+ buffer[7] = 0;
+ send_string(buffer,8);
+ }
+ }
+ lasttime = time;
+ }
+}
+// 1 shunt voltage/
+// 2 bus voltage
+// 3 power
+// 4 current
+// 5 calib 29789 -> 1/8mA
// i2cTx[0]=1; //switch to voltage register
// twi_writeTo(0x47, i2cTx, 1, 1, 1);
// twi_readFrom(0x47, i2cRx, 2, 1);
// twi_writeTo(0x47, i2cTx, 1, 1, 1);
// twi_readFrom(0x47, i2cRx, 2, 1);
// lcd_put_int(((i2cRx[0]<<8)+i2cRx[1])/8);
- }
- }
- lasttime = time;
- }
-}
-// 1 shunt voltage
-// 2 bus voltage
-// 3 power
-// 4 current
-// 5 calib 29789 -> 1/8mA
+