Reorg: replace_constants, resolve_includes.
This commit is contained in:
parent
02ac1e2e4f
commit
97c0fb8e4a
32 changed files with 520 additions and 105 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -1,3 +1,3 @@
|
|||
across
|
||||
stellaris
|
||||
msp430/mecrisp
|
||||
/across
|
||||
/stellaris
|
||||
/msp430/mecrisp
|
||||
|
|
19
README.md
19
README.md
|
@ -63,8 +63,27 @@ Layout
|
|||
- `msp430`: this code is for [mecrisp], 16bit forth running on TI's
|
||||
MSP430G2553 and MSP430FR2433 MCUs. The space is very tight on these
|
||||
(the G2553 with mecrisp has 5kB flash and 160 bytes RAM available).
|
||||
- `scripts`: see below
|
||||
|
||||
|
||||
scripts
|
||||
-------
|
||||
|
||||
### `resolve_includes.py`
|
||||
|
||||
Pretty much all the forth sources here use the convention of using `include`
|
||||
to 'insert the given file here'. [folie] resolves these automatically
|
||||
when sending words to a MCU, but since it is not a forth word, anyone _not_
|
||||
using [folie] is buggered (there are usually many of `include`s and they can
|
||||
be nested).
|
||||
|
||||
So this script produces a single self-contained forth source by resolving
|
||||
all the `include`s (and optionally also `\ on_top_of <file>`). If you are
|
||||
using `*vim`, the included sources should be nicely folded when you open the
|
||||
resulting file.
|
||||
|
||||
Example: `python3 scripts/resolve_includes.py deploy/sbo-sht31/deploy.fs > sbo-all.txt`
|
||||
|
||||
|
||||
[jeenode zero]: https://www.digitalsmarties.net/products/jeenode-zero
|
||||
[embello]: https://git.jeelabs.org/jcw/embello
|
||||
|
|
|
@ -5,5 +5,7 @@ include g6s-base/board.fs
|
|||
include g6s-base/core.fs
|
||||
|
||||
compiletoflash
|
||||
|
||||
include ina219.fs
|
||||
|
||||
compiletoram
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
../../sbo-l041/board.fs
|
68
deploy/sbo-sht31/board.fs
Normal file
68
deploy/sbo-sht31/board.fs
Normal file
|
@ -0,0 +1,68 @@
|
|||
\ on_top_of always.fs
|
||||
\ board definitions
|
||||
|
||||
eraseflash
|
||||
compiletoflash
|
||||
( board start: ) here dup hex.
|
||||
|
||||
include ../../flib/mecrisp/hexdump-min.fs
|
||||
include ../../flib/stm32l0/io-min.fs
|
||||
include ../../flib/pkg/pins20.fs
|
||||
include ../../flib/stm32l0/hal-min.fs
|
||||
include ../../flib/stm32l0/sleep-min.fs
|
||||
include ../../flib/stm32l0/adc-min.fs
|
||||
|
||||
PA1 constant LED \ sbo active low
|
||||
\ PB3 constant LED \ nucleo32 active high
|
||||
PB1 constant BTN \ -1 pressed, 0 not
|
||||
|
||||
: led-off LED ios! ;
|
||||
: led-on LED ioc! ;
|
||||
|
||||
PA4 variable ssel
|
||||
PA5 constant SCLK
|
||||
PA6 constant MISO
|
||||
PA7 constant MOSI
|
||||
include ../../flib/stm32l0/spi-min.fs
|
||||
\ rf69 rf-rssi needs LED
|
||||
include ../../flib/spi/rf69-min.fs
|
||||
|
||||
PA9 constant SCL
|
||||
PA10 constant SDA
|
||||
\ potentially messes up PA0-PA5 as well
|
||||
: i2c-pafs $110 PA9 io-base $24 + ! ; \ (GPIO.AFRH)
|
||||
include ../../flib/stm32l0/i2c-min.fs
|
||||
|
||||
: sleep ( -- ) [ $BF30 h, ] inline ; \ WFI Opcode, enters sleep mode (systick wakes)
|
||||
|
||||
: hello ( -- ) flash-kb . ." KB <n041> " hwid hex.
|
||||
$8000 compiletoflash here - flashvar-here compiletoram here -
|
||||
." ram/flash: " . . ." free " ;
|
||||
|
||||
: init ( -- ) \ board initialisation
|
||||
init \ uses new uart init convention
|
||||
%10001100 $4002102C bic! \ disable ioports C D H (RCC-IOPENR)
|
||||
OMODE-PP LED io-mode!
|
||||
IMODE-FLOAT BTN io-mode!
|
||||
\ 16MHz ( set by Mecrisp on startup to get an accurate USART baud rate )
|
||||
8 $4002104C ! \ set USART2 clock to HSI16, independent of sysclk (sbo uses USART2!!) (RCC-CCIPR)
|
||||
1000 systick-hz
|
||||
led-on
|
||||
hello ." ok." cr
|
||||
;
|
||||
|
||||
: rx-connected? ( -- f ) \ true if RX is connected (and idle)
|
||||
IMODE-LOW PA3 io-mode! sleep PA3 io@ 0<> OMODE-AF-PP PA3 io-mode!
|
||||
dup if sleep serial-key? if serial-key drop then then \ flush any input noise
|
||||
;
|
||||
|
||||
: fake-key? ( -- f ) \ check for RX pin being pulled high
|
||||
rx-connected? if reset then false ;
|
||||
|
||||
: unattended
|
||||
rx-connected? if quit then \ return to command prompt
|
||||
['] fake-key? hook-key? ! ;
|
||||
|
||||
( board end, size: ) here dup hex. swap - .
|
||||
cornerstone <<<board>>>
|
||||
compiletoram
|
3
deploy/sbo-sht31/deploy.fs
Normal file
3
deploy/sbo-sht31/deploy.fs
Normal file
|
@ -0,0 +1,3 @@
|
|||
include always.fs
|
||||
include board.fs
|
||||
include main.fs
|
|
@ -1,7 +1,7 @@
|
|||
\ sensor board deployed with SHT31-D
|
||||
\ when reset with UART connected, it should drop into prompt
|
||||
\ otherwise init devices, deinit USART, slow down and periodically send readings
|
||||
\ needs board.fs
|
||||
\ on_top_of board.fs
|
||||
|
||||
<<<board>>>
|
||||
compiletoflash
|
||||
|
@ -94,7 +94,7 @@ PKTLEN 1+ buffer: packet \ 1+ to make the word-sized params aligned (starts at
|
|||
|
||||
|
||||
\ sensor driver
|
||||
include ../flib/i2c/sht31-d.fs
|
||||
include ../../flib/i2c/sht31-d.fs
|
||||
|
||||
: packet-prepare ( -- ) \ get all measurements (separated for testing)
|
||||
adc-vcc \ get 1000*vdd
|
|
@ -1,5 +1,5 @@
|
|||
\ on_top_of always.fs
|
||||
\ board definitions
|
||||
\ needs always.fs
|
||||
|
||||
eraseflash
|
||||
compiletoflash
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
\ on_top_of board.fs
|
||||
\ core libraries
|
||||
|
||||
<<<board>>>
|
||||
|
|
|
@ -13,7 +13,7 @@ My main concern (because sensors) is power consumption. So some pros and cons.
|
|||
|
||||
This is an amazing one. There is a DIP version of this chip, and with
|
||||
Matthias Koch's venerated `lowpower` version of [mecrisp] it runs _prompt_
|
||||
on about 2uA (requires external 32768 crystal but no caps). The biggest
|
||||
on less than 2uA (requires external 32768 crystal but no caps). The biggest
|
||||
downside is space: it's got only 16kB of flash (of which 11kB takes mecrisp),
|
||||
and 512 bytes of RAM (of which about 200 is available for the program). It is
|
||||
mostly enough for a deployed sensor though (just), but development is a bit
|
||||
|
@ -38,7 +38,8 @@ it is quite a pain to make the MCU use it and switch off REFO. Possible though.
|
|||
This makes `lpm3` pretty nice, just like on g2553. However I couldn't quite
|
||||
make the prompt lowpower (like on g2553), because I didn't find a way to
|
||||
make the UART use the external crystal (XT1) for timing. So it gets shut down
|
||||
on `lpm3`, and while it does wake up on RX, the data is garbled.
|
||||
on `lpm3`, and while it does wake up on RX, the data is garbled. Maybe
|
||||
with lower baud rate?
|
||||
|
||||
### msp430fr2476
|
||||
|
||||
|
@ -46,7 +47,7 @@ Same as fr2433, except 64kB FRAM (only 32kB is below `$FFFF` though, so
|
|||
mecrisp only actively uses that), and 8 kB RAM. Also REFO only uses 1uA here,
|
||||
so one can get reasonably low power in `lpm3` without any components - about 3uA.
|
||||
Comes also in QFP-48 package, so hand solderable.
|
||||
The main downside here is _price_.
|
||||
The main downside here is the _price_.
|
||||
|
||||
## Structure
|
||||
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
<<basis>>
|
||||
compiletoflash
|
||||
include g2553/spi.fs
|
||||
include drivers/rf69.fs
|
||||
include g2553/i2c-bb-base.fs
|
||||
include drivers/i2c-bb.fs
|
||||
reset
|
|
@ -1,3 +1,5 @@
|
|||
The 'lowpower' version needs an external 32768Hz crystal between P2.6 and P2.7 (pins 19 and 18 on MSP430G2553) - because the delays in this one are done with low power sleep, and waking up needs a timer, which needs this external source.
|
||||
|
||||
The 'xt1' versions also need an external 32768Hz crystal on the correct pins; this time with loading caps as well.
|
||||
|
||||
The current `.hex` files are all with mecrisp-2.0.6a.
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
: i2c. ( -- ) \ scan and report all I2C devices on the bus
|
||||
128 0 do
|
||||
cr i h.2 ." :"
|
||||
16 0 do space
|
||||
i j +
|
||||
dup $08 < over $77 > or if drop 2 spaces else
|
||||
dup i2c-addr 0 i2c-xfer if drop ." --" else h.2 then
|
||||
then
|
||||
loop
|
||||
16 +loop ;
|
||||
|
||||
|
|
@ -1,9 +1,12 @@
|
|||
\ rf69 driver; this file contains both tx and rx parts (splittable)
|
||||
\ - slightly modified version of a pretty smart jcw's driver: https://git.jeelabs.org/jcw/embello
|
||||
\ (mainly some 32 vs 16 bit fixes)
|
||||
\ - slightly modified version of a pretty smart jcw's driver:
|
||||
\ https://git.jeelabs.org/jcw/embello
|
||||
\ - mainly some 32 vs 16 bit fixes
|
||||
\ - frequency is hardcoded and non-correctable
|
||||
\ - for the names of registers and bits see the fancy driver
|
||||
\ needs spi
|
||||
\ generate constant-free source with:
|
||||
\ python replace-constants.py rf69.fs rf69-constants.fs
|
||||
\ = 1762 bytes in flash
|
||||
|
||||
\ TX part
|
||||
|
@ -51,18 +54,18 @@ decimal align
|
|||
|
||||
: rf!mode ( b -- ) \ set the radio mode, and store a copy in a variable
|
||||
dup rf.mode !
|
||||
$01 rf@ $E3 and or $01 rf! \ (RF:OP)
|
||||
begin $27 rf@ %10000000 and until ; \ (RF:IRQ1_MRDY @ RF:IRQ1)
|
||||
$01 rf@ $E3 and or $01 rf! \ ($01:RF:OP)
|
||||
begin $27 rf@ %10000000 and until ; \ (%10000000:RF:IRQ1_MRDY) \ ($27:RF:IRQ1)
|
||||
|
||||
: rf-config! ( addr -- ) \ load many registers from <reg,value> array, zero-terminated
|
||||
%00100 rf!mode \ some regs don't program in sleep mode, go figure... \ (RF:M_STDBY)
|
||||
%00100 rf!mode \ some regs don't program in sleep mode, go figure... \ (%00100:RF:M_STDBY)
|
||||
begin dup @ ?dup while rf-h! 2+ repeat drop
|
||||
;
|
||||
|
||||
: rf-group ( u -- ) $31 rf! ; \ set the net group (1..250) \ (RF:SYN3)
|
||||
: rf-group ( u -- ) $31 rf! ; \ set the net group (1..250) \ ($31:RF:SYN3)
|
||||
|
||||
: rf-check ( b -- ) \ check that the register can be accessed over SPI
|
||||
begin dup $2F rf! $2F rf@ over = until \ (RF:SYN1)
|
||||
begin dup $2F rf! $2F rf@ over = until \ ($2F:RF:SYN1)
|
||||
drop ;
|
||||
|
||||
: rf-ini ( group -- ) \ internal init of the RFM69 radio module
|
||||
|
@ -72,41 +75,41 @@ decimal align
|
|||
rf-group ;
|
||||
|
||||
: rf-parity ( -- u ) \ calculate group parity bits
|
||||
$31 rf@ dup 4 lshift xor dup 2 lshift xor $C0 and ; \ (RF:SYN3)
|
||||
$31 rf@ dup 4 lshift xor dup 2 lshift xor $C0 and ; \ ($31:RF:SYN3)
|
||||
|
||||
: rf-n@spi ( addr len -- ) \ read N bytes from the FIFO
|
||||
0 do $00 rf@ over c! 1+ loop drop ; \ (RF:FIFO)
|
||||
0 do $00 rf@ over c! 1+ loop drop ; \ ($00:RF:FIFO)
|
||||
: rf-n!spi ( addr len -- ) \ write N bytes to the FIFO
|
||||
0 do dup c@ $00 rf! 1+ loop drop ; \ (RF:FIFO)
|
||||
0 do dup c@ $00 rf! 1+ loop drop ; \ ($00:RF:FIFO)
|
||||
|
||||
\ this is the intended public API for the RF69 driver
|
||||
|
||||
: rf-power ( n -- ) \ change TX power level (0..31)
|
||||
$11 rf@ $E0 and or $11 rf! ; \ (RF:PA)
|
||||
$11 rf@ $E0 and or $11 rf! ; \ ($11:RF:PA)
|
||||
|
||||
: rf-sleep ( -- ) %00000 rf!mode ; \ put radio module to sleep \ (RF:M_SLEEP)
|
||||
: rf-sleep ( -- ) %00000 rf!mode ; \ put radio module to sleep \ (%00000:RF:M_SLEEP)
|
||||
|
||||
: rf-encrypt ( addr -- ) \ load 16 bytes as AES password, enable encryption
|
||||
$3E 16 + $3E do \ loop by register addr \ (RF:AES)
|
||||
$3E 16 + $3E do \ loop by register addr \ ($3E:RF:AES)
|
||||
dup c@ dup i rf! \ write one, leave ( addr b )
|
||||
if 1+ then \ if b <> 0, advance addr
|
||||
loop drop
|
||||
$3D rf@ 1 or $3D rf! ; \ (RF:PCONF2)
|
||||
$3D rf@ 1 or $3D rf! ; \ ($3D:RF:PCONF2)
|
||||
|
||||
: rf-deencrypt ( -- ) \ clear encryption
|
||||
$3D rf@ $FE and $3D rf! ; \ (RF:PCONF2)
|
||||
$3D rf@ $FE and $3D rf! ; \ ($3D:RF:PCONF2)
|
||||
|
||||
: rf-send ( addr count hdr -- ) \ send out one packet
|
||||
%00100 rf!mode \ (RF:M_STDBY)
|
||||
over 2+ $00 rf! \ (RF:FIFO)
|
||||
dup rf-parity or $00 rf! \ (RF:FIFO)
|
||||
$C0 and rf.nodeid @ or $00 rf! \ (RF:FIFO)
|
||||
%00100 rf!mode \ (%00100:RF:M_STDBY)
|
||||
over 2+ $00 rf! \ ($00:RF:FIFO)
|
||||
dup rf-parity or $00 rf! \ ($00:RF:FIFO)
|
||||
$C0 and rf.nodeid @ or $00 rf! \ ($00:RF:FIFO)
|
||||
( addr count ) rf-n!spi
|
||||
%01100 rf!mode \ (RF:M_TX)
|
||||
begin $28 rf@ %1000 and until \ (RF:IRQ2_SENT @ RF:IRQ2)
|
||||
%00100 rf!mode ; \ (RF:M_STDBY)
|
||||
%01100 rf!mode \ (%01100:RF:M_TX)
|
||||
begin $28 rf@ %00001000 and until \ (%00001000:RF:IRQ2_SENT) \ ($28:RF:IRQ2)
|
||||
%00100 rf!mode ; \ (%00100:RF:M_STDBY)
|
||||
|
||||
: rf-init ( -- ) \ init RFM69 with current rf.group and rf.freq values
|
||||
: rf-init ( -- ) \ init RFM69 with current rf.group
|
||||
rf.group @ rf-ini ;
|
||||
|
||||
: rf-info ( -- ) \ display reception parameters as hex string
|
||||
|
@ -117,43 +120,43 @@ decimal align
|
|||
|
||||
\ rf-timeout checks whether there is an rssi timeout and restarts the receiver if so.
|
||||
: rf-timeout ( -- )
|
||||
$27 rf@ %100 and if \ (RF:IRQ1_TIMEOUT @ RF:IRQ1)
|
||||
%01000 rf!mode \ (RF:M_FS)
|
||||
$27 rf@ %00000100 and if \ (%00000100:RF:IRQ1_TIMEOUT) \ ($27:RF:IRQ1)
|
||||
%01000 rf!mode \ (%01000:RF:M_FS)
|
||||
then ;
|
||||
|
||||
\ rf-status fetches the IRQ1 reg, checks whether rx_sync is set and was not set
|
||||
\ in rf.last. If so, it saves rssi value; and then updates rf.last.
|
||||
\ rf.last ensures that the info is grabbed only once per packet.
|
||||
: rf-status ( -- ) \ update status values on sync match
|
||||
$27 rf@ %1 and rf.last @ <> if \ (RF:IRQ1_SYNC @ RF:IRQ1)
|
||||
rf.last %1 over xor! @ if \ (RF:IRQ1_SYNC)
|
||||
$24 rf@ rf.rssi ! \ (RF:RSSI)
|
||||
$27 rf@ %00000001 and rf.last @ <> if \ (%00000001:RF:IRQ1_SYNC) \ ($27:RF:IRQ1)
|
||||
rf.last %00000001 over xor! @ if \ (%00000001:RF:IRQ1_SYNC)
|
||||
$24 rf@ rf.rssi ! \ ($24:RF:RSSI)
|
||||
then
|
||||
then ;
|
||||
|
||||
\ this is the intended public API for the RF69 driver
|
||||
|
||||
: rf-recv ( -- b ) \ check whether a packet has been received, return #bytes
|
||||
rf.mode @ %10000 <> if \ (RF:M_RX)
|
||||
rf.mode @ %10000 <> if \ (%10000:RF:M_RX)
|
||||
0 rf.rssi !
|
||||
%10000 rf!mode \ (RF:M_RX)
|
||||
%10000 rf!mode \ (%10000:RF:M_RX)
|
||||
else rf-timeout rf-status then
|
||||
$28 rf@ %10 and if \ (RF:IRQ2_CRCOK @ RF:IRQ2)
|
||||
$00 rf@ 66 min \ fetch length and limit \ (RF:FIFO)
|
||||
$28 rf@ %00000010 and if \ (%00000010:RF:IRQ2_CRCOK) \ ($28:RF:IRQ2)
|
||||
$00 rf@ 66 min \ fetch length and limit \ ($00:RF:FIFO)
|
||||
rf.buf over rf-n@spi
|
||||
else 0 then ;
|
||||
|
||||
: rf-ack? ( ms -- b ) \ waits ms milliseconds for an ACK and returns #bytes recv'd
|
||||
0 rf.rssi !
|
||||
%10000 rf!mode \ (RF:M_RX)
|
||||
%10000 rf!mode \ (%10000:RF:M_RX)
|
||||
0 do
|
||||
rf-status \ capture rssi, etc.
|
||||
$28 rf@ %10 and if \ (RF:IRQ2_CRCOK @ RF:IRQ2)
|
||||
$00 rf@ 66 min \ fetch length and limit \ (RF:FIFO)
|
||||
$28 rf@ %00000010 and if \ (%00000010:RF:IRQ2_CRCOK) \ ($28:RF:IRQ2)
|
||||
$00 rf@ 66 min \ fetch length and limit \ ($00:RF:FIFO)
|
||||
rf.buf over rf-n@spi
|
||||
unloop exit
|
||||
then
|
||||
1 ms
|
||||
loop
|
||||
%00100 rf!mode \ kill RX \ (RF:M_STDBY)
|
||||
%00100 rf!mode \ kill RX \ (%00100:RF:M_STDBY)
|
||||
0 ;
|
||||
|
|
|
@ -9,7 +9,7 @@ compiletoflash
|
|||
include port-regs.fs
|
||||
include timer-regs.fs
|
||||
|
||||
: init \ Launchpad hardware initialisations
|
||||
: init
|
||||
." <FR2433> free(flash/ram): " $D400 compiletoflash here compiletoram - . flashvar-here here - . cr
|
||||
;
|
||||
|
||||
|
|
|
@ -8,3 +8,5 @@ compiletoflash
|
|||
%11 P1OUT cbic! \ LEDs off
|
||||
%11 P1DIR cbis! \ LEDs are outputs
|
||||
;
|
||||
|
||||
compiletoram
|
|
@ -9,7 +9,7 @@ compiletoflash
|
|||
include port-regs.fs
|
||||
include timer-regs-min.fs
|
||||
|
||||
: init \ Launchpad hardware initialisations
|
||||
: init
|
||||
." <FR2476> free(flash/ram): " $D400 compiletoflash here compiletoram - . flashvar-here here - . cr
|
||||
;
|
||||
|
||||
|
|
|
@ -8,16 +8,8 @@ compiletoflash
|
|||
does> begin dup $1FF and while 1+ repeat eraseflashfrom
|
||||
;
|
||||
|
||||
: init \ Launchpad hardware initialisations
|
||||
: init
|
||||
." <G2553> free(flash/ram): " $D400 compiletoflash here compiletoram - . flashvar-here here - . cr
|
||||
8 $21 cbis! \ High (P1OUT)
|
||||
8 $27 cbis! \ Pullup for button (P1REN)
|
||||
\ \ 1 64 or $21 cbic! \ LEDs off (P1OUT)
|
||||
\ \ 1 64 or $22 cbis! \ LEDs are outputs (P1DIR)
|
||||
\ 1 $21 cbic! \ red LED off (P1OUT)
|
||||
\ 1 $22 cbis! \ red LED is output (P1DIR) \ P1.6 is MISO
|
||||
\ \ 64 $22 cbis! \ P1.6 is output (if not, launchpad power consumption goes up by 20uA)
|
||||
|
||||
;
|
||||
|
||||
\ Measure Vcc/2 on analog channel 11 with 2.5V reference.
|
11
msp430/g2553/core-g2553.fs
Normal file
11
msp430/g2553/core-g2553.fs
Normal file
|
@ -0,0 +1,11 @@
|
|||
\ on_top_of basis-g2553.fs
|
||||
|
||||
<<basis>>
|
||||
compiletoflash
|
||||
|
||||
include spi.fs
|
||||
include ../drivers/rf69.fs
|
||||
include i2c-bb-base.fs
|
||||
include ../drivers/i2c-bb.fs
|
||||
|
||||
reset
|
|
@ -2,6 +2,7 @@
|
|||
\ There have to be 1..10 kΩ resistors on SDA and SCL to pull them up to idle state.
|
||||
\ Master only. Supports clock stretching.
|
||||
\ hardcoded SCL:P2.4 SDA:P2.5
|
||||
\ from templates/i2c-bb-base.fs with g2553/i2c-bb-base.tmplfill
|
||||
\ 270 bytes flash
|
||||
|
||||
: 0>scl ( -- ) \ drive SCL low
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
\ i2c-bb-base.tmplfill: bitbanged i2c driver template filler for MSP430G2553
|
||||
\ compile into constant-free file with:
|
||||
\ python templates/replace_constants.py templates/i2c-bb-base.fs g2553/i2c-bb-base.tmplfill g2553/pins.fs
|
||||
\ python templates/replace_constants.py templates/i2c-bb-base.fs g2553/i2c-bb-base.tmplfill g2553/port-regs.fs
|
||||
|
||||
%00010000 constant SCLPIN
|
||||
%00100000 constant SDAPIN
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
\ bit-banged i2c driver
|
||||
\ from jcw's embello
|
||||
\ adapted from http://excamera.com/sphinx/article-forth-i2c.html
|
||||
\
|
||||
|
||||
\ This driver is master-only. It supports clock stretching.
|
||||
\ There have to be 1..10 kΩ resistors on SDA and SCL to pull them up to idle state.
|
||||
|
||||
\ by flabbergast: hardcoded SCL:P2.4 SDA:P2.5, modified for MSP430
|
||||
\ it's more complicated than it really needs to be for basic i2c stuff
|
||||
\ 898 bytes flash
|
||||
\ but it is word compatible with jcw's i2c driver for stm32
|
||||
\ = 898 bytes flash
|
||||
|
||||
0 variable i2c.adr
|
||||
0 variable i2c.nak
|
||||
|
@ -95,6 +96,20 @@
|
|||
dup if i2c-stop 0 i2c.cnt ! then \ ignore reads if we had a nak
|
||||
;
|
||||
|
||||
\ extra stuff
|
||||
|
||||
: i2c. ( -- ) \ scan and report all I2C devices on the bus
|
||||
128 0 do
|
||||
cr i h.2 ." :"
|
||||
16 0 do space
|
||||
i j +
|
||||
dup $08 < over $77 > or if drop 2 spaces else
|
||||
dup i2c-addr 0 i2c-xfer if drop ." --" else h.2 then
|
||||
then
|
||||
loop
|
||||
16 +loop ;
|
||||
|
||||
|
||||
|
||||
\ eeprom example (24lc02b, so only one byte address)
|
||||
\ i2c-init
|
||||
|
|
13
msp430/g2553/launchpad.fs
Normal file
13
msp430/g2553/launchpad.fs
Normal file
|
@ -0,0 +1,13 @@
|
|||
\ MSP430G2553 Launchpad-specific words
|
||||
|
||||
compiletoflash
|
||||
|
||||
: init init
|
||||
8 $21 cbis! \ High (P1OUT)
|
||||
8 $27 cbis! \ Pullup for button (P1REN)
|
||||
1 64 or $21 cbic! \ LEDs off (P1OUT)
|
||||
1 64 or $22 cbis! \ LEDs are outputs (P1DIR)
|
||||
\ P1.6 is output: if not, launchpad power consumption goes up by 20uA
|
||||
;
|
||||
|
||||
compiletoram
|
|
@ -1,27 +1,17 @@
|
|||
\ MSP430(G2553) SPI driver
|
||||
\ uses USCI_B0 (P1.5 SCK, P1.6 MISO, P1.7 MOSI) {because USCI_A0 is used for USART}
|
||||
\ hardcoded P2.0 for CS
|
||||
\ (c) 2019 flabbergast
|
||||
\ from templates/g2553-spi.fs with g2553/spi.tmplfill
|
||||
\ hardcoded P2.0 for CS
|
||||
|
||||
\ registers, ref man p444
|
||||
\ UCB0CTL0 068h
|
||||
\ UCB0CTL1 069h
|
||||
\ UCB0BR0 06Ah
|
||||
\ UCB0BR1 06Bh
|
||||
\ UCB0STAT 06Dh
|
||||
\ UCB0RXBUF 06Eh
|
||||
\ UCB0TXBUF 06Fh
|
||||
\ IE2 001h
|
||||
\ IFG2 003h
|
||||
|
||||
: +spi ( -- ) 1 $29 cbic! ; \ select SPI (P2OUT)
|
||||
: -spi ( -- ) 1 $29 cbis! ; \ deselect SPI (P2OUT)
|
||||
: +spi ( -- ) 1 $29 cbic! ; \ select SPI \ (1:SPIPIN) \ (P2OUT:SPIOUT) \ ($29:P2OUT)
|
||||
: -spi ( -- ) 1 $29 cbis! ; \ deselect SPI \ (1:SPIPIN) \ (P2OUT:SPIOUT) \ ($29:P2OUT)
|
||||
|
||||
: >spi> ( c -- c ) \ hardware SPI, 1 byte in, 1 byte out
|
||||
begin %1000 $03 bit@ until \ TXbuf ready? (UCB0TXIFG @ IFG2)
|
||||
begin %1000 $003 bit@ until \ TXbuf ready? \ (%1000:IFG2_UCB0TXIFG) \ ($003:IFG2)
|
||||
$6F c! \ send byte (UCB0TXBUF)
|
||||
begin %0100 $03 bit@ until \ RXbuf ready? (UCB0RXIFG @ IFG2)
|
||||
$6E c@ \ read byte (UCB0RXBUF)
|
||||
begin %0100 $003 bit@ until \ RXbuf ready? \ (%0100:IFG2_UCB0RXIFG) \ ($003:IFG2)
|
||||
$06E c@ \ read byte \ ($06E:UCB0RXBUF)
|
||||
;
|
||||
|
||||
\ single byte shortcuts
|
||||
|
@ -29,12 +19,13 @@
|
|||
: >spi ( c -- ) >spi> drop ; \ write byte to SPI
|
||||
|
||||
: spi-init ( -- ) \ set up hardware SPI
|
||||
-spi 1 $2A cbis! \ setup CS pin (P2DIR)
|
||||
%11100000 $26 cbis! %11100000 $41 cbis! \ setup SCK|MISO|MOSI pins (P1SEL, P1SEL2)
|
||||
1 $69 c! \ put USCI in reset (UCSWRST @ UCB0CTL1)
|
||||
%10101001 $68 c! \ 3-pin 8-bit SPI master (UCCKPH|UCMSB|UCMST|UCSYNC @ UCB0CTL0)
|
||||
%11000000 $69 cbis! \ clock source SMCLK (UCSSELx @ UCB0CTL1)
|
||||
2 $6A c! 0 $6B c! \ prescaler /8 (UCB0BR0, UCB0BR1)
|
||||
1 $69 cbic! \ leave reset, initialize USCI state machine (UCSWRST @ UCB0CTL1)
|
||||
-spi 1 $2A cbis! \ setup CS pin \ (1:SPIPIN) \ (P2DIR:SPIDIR) \ ($2A:P2DIR)
|
||||
%11100000 $26 cbis! \ setup SCK|MISO|MOSI pins \ (%11100000:SPISELBITS) \ (P1SEL:SPISEL) \ ($26:P1SEL)
|
||||
%11100000 $41 cbis! \ setup SCK|MISO|MOSI pins \ (%11100000:SPISELBITS) \ (P1SEL2:SPISEL2) \ ($41:P1SEL2)
|
||||
1 $069 c! \ put USCI in reset (UCSWRST) \ ($069:UCB0CTL1)
|
||||
%10101001 $068 c! \ 3-pin 8-bit SPI master (UCCKPH|UCMSB|UCMST|UCSYNC) \ ($068:UCB0CTL0)
|
||||
%11000000 $069 cbis! \ clock source SMCLK (UCSSELx) \ ($069:UCB0CTL1)
|
||||
2 $06A c! 0 $06B c! \ prescaler /8 \ ($06B:UCB0BR1) \ ($06A:UCB0BR0)
|
||||
1 $069 cbic! \ init USCI (UCSWRST) \ ($069:UCB0CTL1)
|
||||
;
|
||||
|
||||
|
|
11
msp430/g2553/spi.tmplfill
Normal file
11
msp430/g2553/spi.tmplfill
Normal file
|
@ -0,0 +1,11 @@
|
|||
\ spi.tmplfill: template filler for spi driver
|
||||
\ compile into constant-free file with
|
||||
\ python templates/replace_constants.py templates/g2553-spi.fs g2553/spi.tmplfill g2553/usci-regs.fs g2553/port-regs.fs
|
||||
|
||||
1 constant SPIPIN
|
||||
P2OUT constant SPIOUT
|
||||
P2DIR constant SPIDIR
|
||||
P2IN constant SPIIN
|
||||
P1SEL constant SPISEL
|
||||
P1SEL2 constant SPISEL2
|
||||
%11100000 constant SPISELBITS
|
33
msp430/g2553/usci-regs.fs
Normal file
33
msp430/g2553/usci-regs.fs
Normal file
|
@ -0,0 +1,33 @@
|
|||
\ USCI registers
|
||||
\ G2553 datasheet, p19
|
||||
|
||||
$001 constant IE2
|
||||
$003 constant IFG2
|
||||
|
||||
%0001 constant IFG2_UCA0RXIFG
|
||||
%0010 constant IFG2_UCA0TXIFG
|
||||
%0100 constant IFG2_UCB0RXIFG
|
||||
%1000 constant IFG2_UCB0TXIFG
|
||||
|
||||
$05D constant UCA0ABCTL
|
||||
$05E constant UCA0IRTCTL
|
||||
$05F constant UCA0IRRCTL
|
||||
$060 constant UCA0CTL0
|
||||
$061 constant UCA0CTL1
|
||||
$062 constant UCA0BR0
|
||||
$063 constant UCA0BR1
|
||||
$064 constant UCA0MCTL
|
||||
$065 constant UCA0STAT
|
||||
$066 constant UCA0RXBUF
|
||||
$067 constant UCA0TXBUF
|
||||
|
||||
$068 constant UCB0CTL0
|
||||
$069 constant UCB0CTL1
|
||||
$06A constant UCB0BR0
|
||||
$06B constant UCB0BR1
|
||||
$06C constant UCB0CIE
|
||||
$06D constant UCB0STAT
|
||||
$06E constant UCB0RXBUF
|
||||
$06F constant UCB0TXBUF
|
||||
$118 constant UCB0OA
|
||||
$11A constant USB0SA
|
29
msp430/templates/g2553-spi.fs
Normal file
29
msp430/templates/g2553-spi.fs
Normal file
|
@ -0,0 +1,29 @@
|
|||
\ MSP430(G2553) SPI driver
|
||||
\ uses USCI_B0 (P1.5 SCK, P1.6 MISO, P1.7 MOSI) {because USCI_A0 is used for USART}
|
||||
\ (c) 2019 flabbergast
|
||||
|
||||
: +spi ( -- ) SPIPIN SPIOUT cbic! ; \ select SPI
|
||||
: -spi ( -- ) SPIPIN SPIOUT cbis! ; \ deselect SPI
|
||||
|
||||
: >spi> ( c -- c ) \ hardware SPI, 1 byte in, 1 byte out
|
||||
begin IFG2_UCB0TXIFG IFG2 bit@ until \ TXbuf ready?
|
||||
$6F c! \ send byte (UCB0TXBUF)
|
||||
begin IFG2_UCB0RXIFG IFG2 bit@ until \ RXbuf ready?
|
||||
UCB0RXBUF c@ \ read byte
|
||||
;
|
||||
|
||||
\ single byte shortcuts
|
||||
: spi> ( -- c ) 0 >spi> ; \ read byte from SPI
|
||||
: >spi ( c -- ) >spi> drop ; \ write byte to SPI
|
||||
|
||||
: spi-init ( -- ) \ set up hardware SPI
|
||||
-spi SPIPIN SPIDIR cbis! \ setup CS pin
|
||||
SPISELBITS SPISEL cbis! \ setup SCK|MISO|MOSI pins
|
||||
SPISELBITS SPISEL2 cbis! \ setup SCK|MISO|MOSI pins
|
||||
1 UCB0CTL1 c! \ put USCI in reset (UCSWRST)
|
||||
%10101001 UCB0CTL0 c! \ 3-pin 8-bit SPI master (UCCKPH|UCMSB|UCMST|UCSYNC)
|
||||
%11000000 UCB0CTL1 cbis! \ clock source SMCLK (UCSSELx)
|
||||
2 UCB0BR0 c! 0 UCB0BR1 c! \ prescaler /8
|
||||
1 UCB0CTL1 cbic! \ init USCI (UCSWRST)
|
||||
;
|
||||
|
|
@ -14,6 +14,7 @@ replace_dict = {}
|
|||
replace_re = {}
|
||||
comments = re.compile(r"(^[^\\]*)(\\.*|$)")
|
||||
|
||||
# build replacement dictionary along with regexps that check for occurences
|
||||
for filename in args.definitions + [args.template]:
|
||||
with open(filename) as f:
|
||||
for line in f:
|
||||
|
@ -25,7 +26,7 @@ for filename in args.definitions + [args.template]:
|
|||
with open(args.template) as f:
|
||||
for line in f:
|
||||
s = list(comments.match(line.rstrip()).groups())
|
||||
for nam in replace_re:
|
||||
for nam in sorted(replace_re.keys(),reverse=True): # revsort to avoid sub-name clashes
|
||||
upd, k = replace_re[nam].subn(replace_dict[nam], s[0])
|
||||
if k > 0:
|
||||
s[0] = upd
|
||||
|
|
40
msp430/templates/rf69-constants.fs
Normal file
40
msp430/templates/rf69-constants.fs
Normal file
|
@ -0,0 +1,40 @@
|
|||
\ rf69 driver constants
|
||||
|
||||
$00 constant RF:FIFO
|
||||
$01 constant RF:OP
|
||||
$07 constant RF:FRF
|
||||
$11 constant RF:PA
|
||||
$18 constant RF:LNA
|
||||
$1F constant RF:AFC
|
||||
$24 constant RF:RSSI
|
||||
$27 constant RF:IRQ1
|
||||
$28 constant RF:IRQ2
|
||||
$2F constant RF:SYN1
|
||||
$31 constant RF:SYN3
|
||||
$39 constant RF:ADDR
|
||||
$3A constant RF:BCAST
|
||||
$3C constant RF:THRESH
|
||||
$3D constant RF:PCONF2
|
||||
$3E constant RF:AES
|
||||
|
||||
%00000 constant RF:M_SLEEP
|
||||
%00100 constant RF:M_STDBY
|
||||
%01000 constant RF:M_FS
|
||||
%01100 constant RF:M_TX
|
||||
%10000 constant RF:M_RX
|
||||
|
||||
$C2 constant RF:START_TX
|
||||
$42 constant RF:STOP_TX
|
||||
$80 constant RF:RCCALSTART
|
||||
|
||||
%10000000 constant RF:IRQ1_MRDY
|
||||
%01000000 constant RF:IRQ1_RXRDY
|
||||
%00001000 constant RF:IRQ1_RSSI
|
||||
%00000100 constant RF:IRQ1_TIMEOUT
|
||||
%00000001 constant RF:IRQ1_SYNC
|
||||
|
||||
%01000000 constant RF:IRQ2_FIFO_NE
|
||||
%00001000 constant RF:IRQ2_SENT
|
||||
%00000100 constant RF:IRQ2_RECVD
|
||||
%00000010 constant RF:IRQ2_CRCOK
|
||||
|
162
msp430/templates/rf69.fs
Normal file
162
msp430/templates/rf69.fs
Normal file
|
@ -0,0 +1,162 @@
|
|||
\ rf69 driver; this file contains both tx and rx parts (splittable)
|
||||
\ - slightly modified version of a pretty smart jcw's driver:
|
||||
\ https://git.jeelabs.org/jcw/embello
|
||||
\ - mainly some 32 vs 16 bit fixes
|
||||
\ - frequency is hardcoded and non-correctable
|
||||
\ - for the names of registers and bits see the fancy driver
|
||||
\ needs spi
|
||||
\ generate constant-free source with:
|
||||
\ python replace-constants.py rf69.fs rf69-constants.fs
|
||||
\ = 1762 bytes in flash
|
||||
|
||||
\ TX part
|
||||
|
||||
0 variable rf.mode \ last set chip mode
|
||||
0 variable rf.last \ flag used to fetch RSSI only once per packet
|
||||
0 variable rf.rssi \ RSSI signal strength of last reception
|
||||
66 buffer: rf.buf \ buffer with last received packet data
|
||||
|
||||
42 variable rf.group \ network group (1..250)
|
||||
61 variable rf.nodeid \ node ID of this node (1..63)
|
||||
|
||||
create rf:init \ initialise the radio, each 16-bit word is <reg#,val>
|
||||
hex
|
||||
0200 , \ packet mode, fsk
|
||||
0302 , 048A , \ bit rate 49,261 hz
|
||||
0505 , 06C3 , \ 90.3kHzFdev -> modulation index = 2
|
||||
07D9 , 0813 , 0900 , \ 868.3MHz frequency ( freq[Hz] * 2^19 / 32*10^6, MSB )
|
||||
0B20 , \ low M
|
||||
1942 , 1A42 , \ RxBw 125khz, AFCBw 125khz
|
||||
1E0C , \ AFC auto-clear, auto-on
|
||||
2607 , \ disable clkout
|
||||
29C4 , \ RSSI thres -98dB
|
||||
2B40 , \ RSSI timeout after 128 bytes
|
||||
2D05 , \ Preamble 5 bytes
|
||||
2E90 , \ sync size 3 bytes
|
||||
2FAA , \ sync1: 0xAA -- this is really the last preamble byte
|
||||
302D , \ sync2: 0x2D -- actual sync byte
|
||||
312A , \ sync3: network group
|
||||
37D0 , \ drop pkt if CRC fails \ 37D8 h, \ deliver even if CRC fails
|
||||
3842 , \ max 62 byte payload
|
||||
3C8F , \ fifo thres
|
||||
3D12 , \ PacketConfig2, interpkt = 1, autorxrestart on
|
||||
6F20 , \ Test DAGC
|
||||
7102 , \ RegTestAfc
|
||||
0 , \ sentinel
|
||||
decimal align
|
||||
|
||||
\ r/w access to the RF registers
|
||||
: rf!@ ( b reg -- b ) +spi >spi >spi> -spi ;
|
||||
: rf! ( b reg -- ) $80 or rf!@ drop ;
|
||||
: rf@ ( reg -- b ) 0 swap rf!@ ;
|
||||
|
||||
: rf-h! ( h -- ) dup $FF and swap 8 rshift rf! ;
|
||||
|
||||
: rf!mode ( b -- ) \ set the radio mode, and store a copy in a variable
|
||||
dup rf.mode !
|
||||
RF:OP rf@ $E3 and or $01 rf!
|
||||
begin RF:IRQ1 rf@ RF:IRQ1_MRDY and until ;
|
||||
|
||||
: rf-config! ( addr -- ) \ load many registers from <reg,value> array, zero-terminated
|
||||
RF:M_STDBY rf!mode \ some regs don't program in sleep mode, go figure...
|
||||
begin dup @ ?dup while rf-h! 2+ repeat drop
|
||||
;
|
||||
|
||||
: rf-group ( u -- ) RF:SYN3 rf! ; \ set the net group (1..250)
|
||||
|
||||
: rf-check ( b -- ) \ check that the register can be accessed over SPI
|
||||
begin dup RF:SYN1 rf! RF:SYN1 rf@ over = until
|
||||
drop ;
|
||||
|
||||
: rf-ini ( group -- ) \ internal init of the RFM69 radio module
|
||||
spi-init
|
||||
$AA rf-check $55 rf-check \ will hang if there is no radio!
|
||||
rf:init rf-config!
|
||||
rf-group ;
|
||||
|
||||
: rf-parity ( -- u ) \ calculate group parity bits
|
||||
RF:SYN3 rf@ dup 4 lshift xor dup 2 lshift xor $C0 and ;
|
||||
|
||||
: rf-n@spi ( addr len -- ) \ read N bytes from the FIFO
|
||||
0 do RF:FIFO rf@ over c! 1+ loop drop ;
|
||||
: rf-n!spi ( addr len -- ) \ write N bytes to the FIFO
|
||||
0 do dup c@ RF:FIFO rf! 1+ loop drop ;
|
||||
|
||||
\ this is the intended public API for the RF69 driver
|
||||
|
||||
: rf-power ( n -- ) \ change TX power level (0..31)
|
||||
RF:PA rf@ $E0 and or RF:PA rf! ;
|
||||
|
||||
: rf-sleep ( -- ) RF:M_SLEEP rf!mode ; \ put radio module to sleep
|
||||
|
||||
: rf-encrypt ( addr -- ) \ load 16 bytes as AES password, enable encryption
|
||||
RF:AES 16 + RF:AES do \ loop by register addr
|
||||
dup c@ dup i rf! \ write one, leave ( addr b )
|
||||
if 1+ then \ if b <> 0, advance addr
|
||||
loop drop
|
||||
RF:PCONF2 rf@ 1 or RF:PCONF2 rf! ;
|
||||
|
||||
: rf-deencrypt ( -- ) \ clear encryption
|
||||
RF:PCONF2 rf@ $FE and RF:PCONF2 rf! ;
|
||||
|
||||
: rf-send ( addr count hdr -- ) \ send out one packet
|
||||
RF:M_STDBY rf!mode
|
||||
over 2+ RF:FIFO rf!
|
||||
dup rf-parity or RF:FIFO rf!
|
||||
$C0 and rf.nodeid @ or RF:FIFO rf!
|
||||
( addr count ) rf-n!spi
|
||||
RF:M_TX rf!mode
|
||||
begin RF:IRQ2 rf@ RF:IRQ2_SENT and until
|
||||
RF:M_STDBY rf!mode ;
|
||||
|
||||
: rf-init ( -- ) \ init RFM69 with current rf.group
|
||||
rf.group @ rf-ini ;
|
||||
|
||||
: rf-info ( -- ) \ display reception parameters as hex string
|
||||
rf.group @ h.2 rf.rssi @ h.2 ;
|
||||
|
||||
|
||||
\ RX part
|
||||
|
||||
\ rf-timeout checks whether there is an rssi timeout and restarts the receiver if so.
|
||||
: rf-timeout ( -- )
|
||||
RF:IRQ1 rf@ RF:IRQ1_TIMEOUT and if
|
||||
RF:M_FS rf!mode
|
||||
then ;
|
||||
|
||||
\ rf-status fetches the IRQ1 reg, checks whether rx_sync is set and was not set
|
||||
\ in rf.last. If so, it saves rssi value; and then updates rf.last.
|
||||
\ rf.last ensures that the info is grabbed only once per packet.
|
||||
: rf-status ( -- ) \ update status values on sync match
|
||||
RF:IRQ1 rf@ RF:IRQ1_SYNC and rf.last @ <> if
|
||||
rf.last RF:IRQ1_SYNC over xor! @ if
|
||||
RF:RSSI rf@ rf.rssi !
|
||||
then
|
||||
then ;
|
||||
|
||||
\ this is the intended public API for the RF69 driver
|
||||
|
||||
: rf-recv ( -- b ) \ check whether a packet has been received, return #bytes
|
||||
rf.mode @ RF:M_RX <> if
|
||||
0 rf.rssi !
|
||||
RF:M_RX rf!mode
|
||||
else rf-timeout rf-status then
|
||||
RF:IRQ2 rf@ RF:IRQ2_CRCOK and if
|
||||
RF:FIFO rf@ 66 min \ fetch length and limit
|
||||
rf.buf over rf-n@spi
|
||||
else 0 then ;
|
||||
|
||||
: rf-ack? ( ms -- b ) \ waits ms milliseconds for an ACK and returns #bytes recv'd
|
||||
0 rf.rssi !
|
||||
RF:M_RX rf!mode
|
||||
0 do
|
||||
rf-status \ capture rssi, etc.
|
||||
RF:IRQ2 rf@ RF:IRQ2_CRCOK and if
|
||||
RF:FIFO rf@ 66 min \ fetch length and limit
|
||||
rf.buf over rf-n@spi
|
||||
unloop exit
|
||||
then
|
||||
1 ms
|
||||
loop
|
||||
RF:M_STDBY rf!mode \ kill RX
|
||||
0 ;
|
|
@ -1,5 +1,5 @@
|
|||
\ on_top_of always.fs
|
||||
\ board definitions
|
||||
\ needs always.fs
|
||||
|
||||
eraseflash
|
||||
compiletoflash
|
||||
|
|
35
scripts/resolve_includes.py
Executable file
35
scripts/resolve_includes.py
Executable file
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import argparse
|
||||
|
||||
|
||||
def print_file(abspath,ontop=False,depth=0):
|
||||
(dirname,filename) = os.path.split(abspath)
|
||||
beginnote = ' '*4*depth + '\ {{{ ' + ('='*5*(depth+1)) + ' included %s%s =====\n'
|
||||
endnote = ' '*4*depth + '\ }}} ' + ('='*5*(depth+1)) + ' end of included %s =====\n'
|
||||
with open(abspath) as f:
|
||||
for line in f:
|
||||
if line.startswith('include '):
|
||||
newfile = line.split()[1]
|
||||
print(beginnote % ('', os.path.basename(newfile)))
|
||||
print_file(os.path.abspath(os.path.join(dirname,newfile)),ontop=ontop,depth=depth+1)
|
||||
print(endnote % os.path.basename(newfile))
|
||||
elif ontop and line.startswith('\\ on_top_of'):
|
||||
newfile = line.split()[2]
|
||||
print(beginnote % ('(on_top_of) ', os.path.basename(newfile)))
|
||||
print_file(os.path.abspath(os.path.join(dirname,newfile)),ontop=ontop,depth=depth+1)
|
||||
print(endnote % os.path.basename(newfile))
|
||||
else:
|
||||
print(' '*4*depth + line.rstrip())
|
||||
|
||||
|
||||
argparser = argparse.ArgumentParser(description='Recursively replace ''include'' in forth sources by contents. No files changed, output will be send to stdout.')
|
||||
argparser.add_argument('file', help='File to start with')
|
||||
argparser.add_argument('-o', '--on_top_of', action='store_true', help='Resolve also "\ on_top_of"')
|
||||
#argparser.add_argument('definitions', nargs='*', help='Where to read the constants from')
|
||||
args = argparser.parse_args()
|
||||
|
||||
print_file(args.file,ontop=args.on_top_of,depth=0)
|
||||
|
||||
print('\n\ vim: filetype=forth:foldmethod=marker:')
|
Loading…
Reference in a new issue