From ee4e71da1abf21da5696687e253c5cfaae124110 Mon Sep 17 00:00:00 2001 From: Michael Moon Date: Fri, 5 Mar 2010 21:24:10 +1100 Subject: [PATCH] preliminary support for line numbers and checksums, also some handy host-side functions --- mendel/Makefile | 20 +++-- mendel/func.sh | 206 ++++++++++++++++++++++++++++++++++++++++++++++++ mendel/gcode.c | 90 ++++++++++++++++----- mendel/gcode.h | 10 ++- mendel/sermsg.c | 2 +- 5 files changed, 303 insertions(+), 25 deletions(-) create mode 100644 mendel/func.sh diff --git a/mendel/Makefile b/mendel/Makefile index f37ce3f..d6be700 100644 --- a/mendel/Makefile +++ b/mendel/Makefile @@ -36,9 +36,14 @@ CC = $(ARCH)gcc OBJDUMP = $(ARCH)objdump OBJCOPY = $(ARCH)objcopy +DEFS = -DF_CPU=$(F_CPU) +# DEFS += "-DDEBUG=1" +# DEFS += "-DREQUIRE_LINENUMBER" +# DEFS += "-DREQUIRE_CHECKSUM" + OPTIMIZE = -Os -ffunction-sections -finline-functions-called-once -DDEBUG=0 # OPTIMIZE = -O0 -CFLAGS = -g -Wall -Wstrict-prototypes $(OPTIMIZE) -mmcu=$(MCU_TARGET) -DF_CPU=$(F_CPU) $(DEFS) -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -save-temps +CFLAGS = -g -Wall -Wstrict-prototypes $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS) -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -save-temps LDFLAGS = -Wl,--as-needed -Wl,--gc-sections AVRDUDE = avrdude @@ -52,14 +57,14 @@ AVRDUDE = avrdude # # ############################################################################## PROGPORT = /dev/arduino -PROGBAUD = 19200 +PROGBAUD = 57600 OBJ = $(patsubst %.c,%.o,${SOURCES}) .PHONY: all program clean size .PRECIOUS: %.o %.elf -all: $(PROGRAM).hex $(PROGRAM).lst size +all: $(PROGRAM).hex $(PROGRAM).lst $(PROGRAM).sym size program: $(PROGRAM).hex stty $(PROGBAUD) raw ignbrk hup < $(PROGPORT) @@ -72,8 +77,9 @@ clean: rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex *.al *.i *.s *~ size: $(PROGRAM).hex - @echo -n " SIZE " - @objdump -h mendel.elf | perl -ne '/.(data|text)\s+([0-9a-f]+)/ && do { $$a += eval "0x$$2" }; END { printf "%d bytes (%d%% of %dkb)\n", $$a, $$a * 100 / (14 * 1024), 14 }' + @echo " SIZE Atmega168 Atmega328p" + @objdump -h mendel.elf | perl -ne '/.(text)\s+([0-9a-f]+)/ && do { $$a += eval "0x$$2" }; END { printf " FLASH: %5d bytes (%2d%% of %2dkb) (%2d%% of %2dkb)\n", $$a, $$a * 100 / (14 * 1024), 14, $$a * 100 / (30 * 1024), 30 }' + @objdump -h mendel.elf | perl -ne '/.(data|bss)\s+([0-9a-f]+)/ && do { $$a += eval "0x$$2" }; END { printf " RAM : %5d bytes (%2d%% of %2dkb) (%2d%% of %2dkb)\n", $$a, $$a * 100 / (1 * 1024), 1, $$a * 100 / (2 * 1024), 2 }' %.o: %.c @echo " CC $@" @@ -94,3 +100,7 @@ size: $(PROGRAM).hex %.bin: %.elf @echo " OBJCOPY $@" @$(OBJCOPY) -j .text -j .data -O binary $< $@ + +%.sym: %.elf + @echo " SYM $@" + @$(OBJDUMP) -t $< | perl -ne 'BEGIN { printf " ADDR NAME SIZE\n"; } /([0-9a-f]+)\s+(\w+)\s+O\s+\.(bss|data)\s+([0-9a-f]+)\s+(\w+)/ && printf "0x%04x %-20s +%d\n", eval("0x$$1") & 0xFFFF, $$5, eval("0x$$4")' | sort -k1 > $@ \ No newline at end of file diff --git a/mendel/func.sh b/mendel/func.sh new file mode 100644 index 0000000..38ce895 --- /dev/null +++ b/mendel/func.sh @@ -0,0 +1,206 @@ +#!/bin/bash + +# +# this file is designed to be sourced into your current shell like this: +# +# source ./func.sh +# +# and then used like this: +# +# $ arduincmd G1 X100 +# $ arduinocmd M250 +# +# {X:4200,Y:0,Z:0,E:0,F:300,c:19334400} +# {X:4200,Y:0,Z:0,E:0,F:300,c:0} +# Q1/1E +# $ readsym_uint8 mb_head +# 1 +# $ readsym_target startpoint +# X: 2100 +# Y: 0 +# Z: 0 +# E: 0 +# F: 300 +# $ readsym_mb +# [0] { +# eX: 0 eY: 0 eZ: 0 eE: 0 eF: 0 +# flags: 0 +# dX: 0 dY: 0 dZ: 0 dE: 0 +# cX: 0 cY: 0 cZ: 0 cE: 0 +# ts: 0 +# c: 0 ec: 0 n: 0 +# } +# [HEAD,TAIL:1] { +# eX: 4200 eY: 0 eZ: 0 eE: 0 eF: 300 +# flags: 120 +# dX: 4200 dY: 0 dZ: 0 dE: 0 +# cX: -2100 cY: -2100 cZ: -2100 cE: -2100 +# ts: 4200 +# c: 19334400 ec: 0 n: 0 +# } +# [2] { +# eX: 0 eY: 0 eZ: 0 eE: 0 eF: 0 +# flags: 0 +# dX: 0 dY: 0 dZ: 0 dE: 0 +# cX: 0 cY: 0 cZ: 0 cE: 0 +# ts: 0 +# c: 0 ec: 0 n: 0 +# } +# [3] { +# eX: 0 eY: 0 eZ: 0 eE: 0 eF: 0 +# flags: 0 +# dX: 0 dY: 0 dZ: 0 dE: 0 +# cX: 0 cY: 0 cZ: 0 cE: 0 +# ts: 0 +# c: 0 ec: 0 n: 0 +# } +# [4] { +# eX: 0 eY: 0 eZ: 0 eE: 0 eF: 0 +# flags: 0 +# dX: 0 dY: 0 dZ: 0 dE: 0 +# cX: 0 cY: 0 cZ: 0 cE: 0 +# ts: 0 +# c: 0 ec: 0 n: 0 +# } +# [5] { +# eX: 0 eY: 0 eZ: 0 eE: 0 eF: 0 +# flags: 0 +# dX: 0 dY: 0 dZ: 0 dE: 0 +# cX: 0 cY: 0 cZ: 0 cE: 0 +# ts: 0 +# c: 0 ec: 0 n: 0 +# } +# [6] { +# eX: 0 eY: 0 eZ: 0 eE: 0 eF: 0 +# flags: 0 +# dX: 0 dY: 0 dZ: 0 dE: 0 +# cX: 0 cY: 0 cZ: 0 cE: 0 +# ts: 0 +# c: 0 ec: 0 n: 0 +# } +# [7] { +# eX: 0 eY: 0 eZ: 0 eE: 0 eF: 0 +# flags: 0 +# dX: 0 dY: 0 dZ: 0 dE: 0 +# cX: 0 cY: 0 cZ: 0 cE: 0 +# ts: 0 +# c: 0 ec: 0 n: 0 +# } + + + + +arduinocmd() { + ( + LN=0 + cmd="$*" + echo "$cmd" >&3; + while [ "$REPLY" != "OK" ] + do + read -u 3 + if [ "$LN" -ne 0 ] + then + if [ "$REPLY" != "OK" ] + then + echo "$REPLY" + fi + fi + LN=$(( $LN + 1 )) + done + ) 3<>/dev/arduino; +} + +readsym() { + sym=$1 + make mendel.sym &>/dev/null + if egrep -q '\b'$sym'\b' mendel.sym + then + ADDR=$(( $(egrep '\b'$sym'\b' mendel.sym | cut -d\ -f1) )) + SIZE=$(egrep '\b'$sym'\b' mendel.sym | cut -d+ -f2) + while [ $SIZE -gt 0 ] + do + echo -n $(arduinocmd "M253 S"$ADDR) + ADDR=$(( $ADDR + 1 )) + SIZE=$(( $SIZE - 1 )) + done + echo + else + echo "unknown symbol: $sym" + fi +} + +readsym_uint8() { + sym=$1 + val=$(readsym $sym) + perl -e 'printf "%u\n", eval "0x".$ARGV[0]' $val +} + +readsym_int8() { + sym=$1 + val=$(readsym $sym) + perl -e 'printf "%d\n", ((eval "0x".$ARGV[0]) & 0x7F) - (((eval "0x".$ARGV[0]) & 0x80)?0x80:0)' $val +} + +readsym_uint16() { + sym=$1 + val=$(readsym $sym) + perl -e '$ARGV[0] =~ m#(..)(..)# && printf "%u\n", eval "0x$2$1"' $val +} + +readsym_int16() { + sym=$1 + val=$(readsym $sym) + perl -e '$ARGV[0] =~ m#(..)(..)# && printf "%d\n", ((eval "0x$2$1") & 0x7FFF) - (((eval "0x$2$1") & 0x8000)?0x8000:0)' $val +} + +readsym_uint32() { + sym=$1 + val=$(readsym $sym) + perl -e '$ARGV[0] =~ m#(..)(..)(..)(..)# && printf "%u\n", eval "0x$4$3$2$1"' $val +} + +readsym_int32() { + sym=$1 + val=$(readsym $sym) + perl -e '$ARGV[0] =~ m#(..)(..)(..)(..)# && printf "%d\n", eval "0x$4$3$2$1"' $val +} + +readsym_target() { + sym=$1 + val=$(readsym $sym) + perl -e '@a = qw/X Y Z E F/; $c = 0; while (length $ARGV[0]) { $ARGV[0] =~ s#^(..)(..)(..)(..)##; printf "%s: %d\n", $a[$c], eval "0x$4$3$2$1"; $c++; }' $val +} + +readsym_mb() { + val=$(readsym movebuffer) + mbhead=$(readsym mb_head) + mbtail=$(readsym mb_tail) + perl - <<'ENDPERL' -- $val $mbhead $mbtail + $i = -1; + @a = qw/eX 4 eY 4 eZ 4 eE 4 eF 4 flags 9 dX 12 dY 4 dZ 4 dE 4 cX 12 cY 4 cZ 4 cE 4 ts 12 c 12 ec 4 n 4/; + $c = 0; + $c = 1234567; + while (length $ARGV[1]) { + if ($c > ($#a / 2)) { + $i++; + $c = 0; + printf "\n}\n" + if ($i > 0); + printf "[%s%d] {\n", (($i == $ARGV[2])?"HEAD":"").(($ARGV[2] == $ARGV[3] && $ARGV[2] == $i)?",":"").(($i == $ARGV[3])?"TAIL":"").(($i == $ARGV[2] || $i == $ARGV[3])?":":""), $i + } + if ($a[$c * 2 + 1] & 8) { + printf "\n"; + } + if (($a[$c * 2 + 1] & 7) == 4) { + $ARGV[1] =~ s#^(..)(..)(..)(..)##; + printf "\t%s: %d", $a[$c * 2], eval "0x$4$3$2$1"; + } + elsif (($a[$c * 2 + 1] & 7) == 1) { + $ARGV[1] =~ s#^(..)##; + printf "\t%s: %d", $a[$c * 2], eval "0x$1"; + } + $c++; + } + printf "\n}\n"; +ENDPERL +} \ No newline at end of file diff --git a/mendel/gcode.c b/mendel/gcode.c index efbd861..1b88305 100644 --- a/mendel/gcode.c +++ b/mendel/gcode.c @@ -14,12 +14,13 @@ uint8_t option_bitfield; #define OPTION_COMMENT 128 +#define OPTION_CHECKSUM 64 decfloat read_digit; -const char alphabet[] = "GMXYZEFSP"; +const char alphabet[] = "GMXYZEFSPN*"; -GCODE_COMMAND next_target = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0 } }; +GCODE_COMMAND next_target = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0 }; /* utility functions @@ -96,9 +97,20 @@ void SpecialMoveE(int32_t e, uint32_t f) { enqueue(&t); } +/**************************************************************************** +* * +* Character Received - add it to our command * +* * +****************************************************************************/ + void scan_char(uint8_t c) { static uint8_t last_field = 0; + // move this below switch(c) if the asterisk isn't included in the checksum + #define crc(a, b) (a ^ b) + if ((option_bitfield & OPTION_CHECKSUM) == 0) + next_target.checksum_calculated = crc(next_target.checksum_calculated, c); + // uppercase if (c >= 'a' && c <= 'z') c &= ~32; @@ -182,6 +194,12 @@ void scan_char(uint8_t c) { // if (DEBUG) serwrite_uint16(next_target.P); break; + case 'N': + next_target.N = decfloat_to_int(&read_digit, 1, 1); + break; + case '*': + next_target.checksum_read = decfloat_to_int(&read_digit, 1, 1); + break; } // reset for next field last_field = 0; @@ -234,6 +252,13 @@ void scan_char(uint8_t c) { case 'P': next_target.seen_P = 1; break; + case 'N': + next_target.seen_N = 1; + break; + case '*': + next_target.seen_checksum = 1; + option_bitfield |= OPTION_CHECKSUM; + break; // comments case ';': @@ -269,23 +294,47 @@ void scan_char(uint8_t c) { serial_writechar(c); // process if (next_target.seen_G || next_target.seen_M) { - process_gcode_command(&next_target); + if ( + #ifdef REQUIRE_LINENUMBER + ((next_target.N_expected == next_target.N) && (next_target.seen_N == 1)) && + #else + ((next_target.N_expected == next_target.N) || (next_target.seen_N == 0)) && + #endif + #ifdef REQUIRE_CHECKSUM + ((next_target.checksum_calculated == next_target.checksum_read) && (next_target.seen_checksum == 1)) + #else + ((next_target.checksum_calculated == next_target.checksum_read) || (next_target.seen_checksum == 0)) + #endif + ) { + process_gcode_command(&next_target); - // reset 'seen comment' - option_bitfield &= ~OPTION_COMMENT; + serial_writestr_P(PSTR("OK\n")); - // reset variables - next_target.seen_X = next_target.seen_Y = next_target.seen_Z = next_target.seen_E = next_target.seen_F = next_target.seen_S = next_target.seen_P = 0; - last_field = 0; - read_digit.sign = 0; - read_digit.mantissa = 0; - read_digit.exponent = 0; - - serial_writestr_P(PSTR("OK\n")); + // expect next line number + next_target.N_expected++; + } + else { + serial_writestr_P(PSTR("RESEND\n")); + } } + // reset 'seen comment' and 'receiving checksum' + option_bitfield = 0; + + // reset variables + next_target.seen_X = next_target.seen_Y = next_target.seen_Z = next_target.seen_E = next_target.seen_F = next_target.seen_S = next_target.seen_P = next_target.N = next_target.checksum_read = next_target.checksum_calculated = 0; + last_field = 0; + read_digit.sign = 0; + read_digit.mantissa = 0; + read_digit.exponent = 0; } } +/**************************************************************************** +* * +* Command Received - process it * +* * +****************************************************************************/ + void process_gcode_command(GCODE_COMMAND *gcmd) { // convert relative to absolute if (gcmd->option_relative) { @@ -535,18 +584,22 @@ void process_gcode_command(GCODE_COMMAND *gcmd) { serwrite_int32(current_position.E); serial_writestr_P(PSTR(",F:")); serwrite_int32(current_position.F); + serial_writestr_P(PSTR(",c:")); + serwrite_uint32(movebuffer[mb_tail].c); serial_writestr_P(PSTR("}\n")); serial_writestr_P(PSTR("{X:")); - serwrite_int32(startpoint.X); + serwrite_int32(movebuffer[mb_tail].endpoint.X); serial_writestr_P(PSTR(",Y:")); - serwrite_int32(startpoint.Y); + serwrite_int32(movebuffer[mb_tail].endpoint.Y); serial_writestr_P(PSTR(",Z:")); - serwrite_int32(startpoint.Z); + serwrite_int32(movebuffer[mb_tail].endpoint.Z); serial_writestr_P(PSTR(",E:")); - serwrite_int32(startpoint.E); + serwrite_int32(movebuffer[mb_tail].endpoint.E); serial_writestr_P(PSTR(",F:")); - serwrite_int32(startpoint.F); + serwrite_int32(movebuffer[mb_tail].endpoint.F); + serial_writestr_P(PSTR(",c:")); + serwrite_uint32(movebuffer[mb_tail].end_c); serial_writestr_P(PSTR("}\n")); print_queue(); @@ -555,6 +608,7 @@ void process_gcode_command(GCODE_COMMAND *gcmd) { // DEBUG: read arbitrary memory location case 253: serwrite_hex8(*(volatile uint8_t *)(gcmd->S)); + serial_writechar('\n'); break; // DEBUG: write arbitrary memory locatiom diff --git a/mendel/gcode.h b/mendel/gcode.h index b0187ea..7207f3b 100644 --- a/mendel/gcode.h +++ b/mendel/gcode.h @@ -22,11 +22,13 @@ typedef struct { uint8_t seen_E :1; uint8_t seen_F :1; uint8_t seen_S :1; + uint8_t seen_P :1; + uint8_t seen_N :1; + uint8_t seen_checksum :1; uint8_t option_relative :1; uint8_t option_inches :1; -// uint8_t option_synchronise :1; uint8_t G; uint8_t M; @@ -34,6 +36,12 @@ typedef struct { int16_t S; uint16_t P; + + uint32_t N; + uint32_t N_expected; + + uint8_t checksum_read; + uint8_t checksum_calculated; } GCODE_COMMAND; // the command being processed diff --git a/mendel/sermsg.c b/mendel/sermsg.c index 97a0dae..87eaa13 100644 --- a/mendel/sermsg.c +++ b/mendel/sermsg.c @@ -7,7 +7,7 @@ void serwrite_hex4(uint8_t v) { if (v < 10) serial_writechar('0' + v); else - serial_writechar('A' + v); + serial_writechar('A' - 10 + v); } void serwrite_hex8(uint8_t v) {