ARDUINO = '/Applications/Arduino\\ 1.5.7.app/Contents/Resources/Java'
RUSTC   = '/usr/local/bin/rustc'
LLC     = '/usr/local/Cellar/llvm35-with-arm/3.5.0/bin/llc-3.5'

PORT = ENV['ARDUINO_DUE_PORT'] || "tty.usbmodemfd1421"

RUST_SRC = 'core.rs'

# ---------------------------------------------------------------
# Normally you shouldn't need to change anything below this line!
# ---------------------------------------------------------------

USR_C_SRCS = []
USR_CPP_SRCS = []
USR_INCLUDES = []

# ----------------------------------------------------------------------
# Normally you really shouldn't need to change anything below this line!
# ----------------------------------------------------------------------

AR      = "#{ARDUINO}/hardware/tools/gcc-arm-none-eabi-4.8.3-2014q1/bin/arm-none-eabi-ar"
CC      = "#{ARDUINO}/hardware/tools/gcc-arm-none-eabi-4.8.3-2014q1/bin/arm-none-eabi-gcc"
CXX     = "#{ARDUINO}/hardware/tools/gcc-arm-none-eabi-4.8.3-2014q1/bin/arm-none-eabi-g++"
OBJCOPY = "#{ARDUINO}/hardware/tools/gcc-arm-none-eabi-4.8.3-2014q1/bin/arm-none-eabi-objcopy"

C_SRCS = ['hardware/arduino/sam/cores/arduino/cortex_handlers.c', 'hardware/arduino/sam/cores/arduino/hooks.c', 'hardware/arduino/sam/cores/arduino/itoa.c', 'hardware/arduino/sam/cores/arduino/WInterrupts.c', 'hardware/arduino/sam/cores/arduino/wiring.c', 'hardware/arduino/sam/cores/arduino/wiring_analog.c', 'hardware/arduino/sam/cores/arduino/wiring_digital.c', 'hardware/arduino/sam/cores/arduino/wiring_shift.c', 'hardware/arduino/sam/cores/arduino/iar_calls_sam3.c', 'hardware/arduino/sam/cores/arduino/syscalls_sam3.c'] + USR_C_SRCS

CPP_SRCS = ['hardware/arduino/sam/cores/arduino/cxxabi-compat.cpp', 'hardware/arduino/sam/cores/arduino/IPAddress.cpp', 'hardware/arduino/sam/cores/arduino/Print.cpp', 'hardware/arduino/sam/cores/arduino/Reset.cpp', 'hardware/arduino/sam/cores/arduino/RingBuffer.cpp', 'hardware/arduino/sam/cores/arduino/Stream.cpp', 'hardware/arduino/sam/cores/arduino/UARTClass.cpp', 'hardware/arduino/sam/cores/arduino/USARTClass.cpp', 'hardware/arduino/sam/cores/arduino/USB/CDC.cpp', 'hardware/arduino/sam/cores/arduino/USB/HID.cpp', 'hardware/arduino/sam/cores/arduino/USB/USBCore.cpp', 'hardware/arduino/sam/cores/arduino/wiring_pulse.cpp', 'hardware/arduino/sam/cores/arduino/WMath.cpp', 'hardware/arduino/sam/cores/arduino/WString.cpp', 'hardware/arduino/sam/variants/arduino_due_x/variant.cpp'] + USR_CPP_SRCS

INCLUDES = ['hardware/arduino/sam/system/libsam', 'hardware/arduino/sam/system/CMSIS/CMSIS/Include',
'hardware/arduino/sam/cores/arduino',
'hardware/arduino/sam/system/CMSIS/Device/ATMEL', 'hardware/arduino/sam/variants/arduino_due_x'] + USR_INCLUDES

@cflags = '-c -g -Os -w -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -Dprintf=iprintf -mcpu=cortex-m3 -DF_CPU=84000000L -DARDUINO=155 -DARDUINO_SAM_DUE -DARDUINO_ARCH_SAM -D__SAM3X8E__ -mthumb -DUSB_VID=0x2341 -DUSB_PID=0x003e -DUSBCON ' + INCLUDES.map { |x| "-I#{x}" }.join(' ')

@cxxflags = "#{@cflags} -fno-rtti -fno-exceptions"

@ldflags = '-Os -Wl,--gc-sections -mcpu=cortex-m3'
@ldflags += " -T#{ARDUINO}/hardware/arduino/sam/variants/arduino_due_x/linker_scripts/gcc/flash.ld"
@ldflags += ' -Loutput'
@ldflags += ' -lm -lgcc -mthumb -Wl,--cref'
@ldflags += ' -Wl,--check-sections'
@ldflags += ' -Wl,--gc-sections'
@ldflags += ' -Wl,--entry=Reset_Handler'
@ldflags += ' -Wl,--unresolved-symbols=report-all'
@ldflags += ' -Wl,--warn-common'
@ldflags += ' -Wl,--warn-section-align'
@ldflags += ' -Wl,--warn-unresolved-symbols'
@ldflags += ' -Wl,--start-group'
@ldflags += " #{ARDUINO}/hardware/arduino/sam/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a"
@ldflags += ' output/arduino.a'
@ldflags += ' output/core.o'
@ldflags += ' -Wl,--end-group'

task :all => :core
task :core => 'output/core.bin'
task :clean do
  sh 'rm -r output/'
end

task :flash => :core do
  # Upload to Programming Port
  if ENV['DUE_PORT'] != 'native'
    require 'SerialPort'
    SerialPort.open("/dev/#{PORT}", 1200) {|sp| puts "Reset Board" }
  end
  sh "#{ARDUINO}/hardware/tools/bossac --port=#{PORT} -U false -e -w -v -b output/core.bin -R"
end

directory 'output'

file 'output/core.s' => [RUST_SRC, 'arduino.rs', 'output'] do
  sh "#{RUSTC} --target arm-unknown-linux-gnueabihf --crate-type=lib --emit=llvm-ir -C no-stack-check -o output/main.ll -A non-upper-case-globals -A unused-imports -A dead-code -A non-snake-case -v #{RUST_SRC}"
  sh "sed -i .1 's/arm-unknown-linux-gnueabihf/arm-none-eabi/g' output/main.ll"
  # This prevents an error: invalid use of function-only attribute
  sh "sed -i .1 's/nocapture readonly/nocapture/g' output/main.ll"
  sh "#{LLC} -march=thumb -mattr=+thumb2 -mcpu=cortex-m3 --float-abi=soft -asm-verbose output/main.ll -o=output/core.s"
end

file 'output/core.o' => 'output/core.s' do
  sh "#{CC} #{@cflags} output/core.s -o output/core.o"
end

file 'output/core.elf' => ['output/core.o', 'output/arduino.a'] do
  sh "#{CXX} #{@ldflags} -o output/core.elf"
end

file 'output/core.bin' => 'output/core.elf' do
  sh "#{OBJCOPY} -O binary output/core.elf output/core.bin"
end

file 'output/arduino.a' => ['output'] do
  C_SRCS.each do |src|
    output = "output/#{File.basename(src, '.c')}.o"
    sh "#{CC} #{@cflags} #{src} -o '#{output}'"
    sh "#{AR} rcs output/arduino.a '#{output}'"
  end

  CPP_SRCS.each do |src|
    output = "output/#{File.basename(src, '.cpp')}.o"
    sh "#{CXX} #{@cxxflags} #{src} -o '#{output}'"
    sh "#{AR} rcs output/arduino.a '#{output}'"
  end
end
