diff options
| author | Bdale Garbee <bdale@gag.com> | 2017-04-24 18:22:03 -0600 | 
|---|---|---|
| committer | Bdale Garbee <bdale@gag.com> | 2017-04-24 18:22:03 -0600 | 
| commit | b91f67005709cb7f65e0a461b49b5cb0952cb391 (patch) | |
| tree | e9f6c0f30a81cf30a9cfd52887171168f7830f85 /src | |
| parent | 1e956f93e0c9f8ed6180490f80e8aead5538f818 (diff) | |
| parent | 8a10ddb0bca7d6f6aa4aedda171899abd165fd74 (diff) | |
Merge branch 'branch-1.7' into debian
Diffstat (limited to 'src')
186 files changed, 20030 insertions, 179 deletions
diff --git a/src/avr/ao_avr_stdio.c b/src/avr/ao_avr_stdio.c index cca2a971..fde3c421 100644 --- a/src/avr/ao_avr_stdio.c +++ b/src/avr/ao_avr_stdio.c @@ -21,6 +21,7 @@  int  stdio_put(char c, FILE *stream)  { +	(void) stream;  	putchar(c);  	return 0;  } @@ -28,6 +29,7 @@ stdio_put(char c, FILE *stream)  int  stdio_get(FILE *stream)  { +	(void) stream;  	return (int) getchar() & 0xff;  } diff --git a/src/cc1111/ao_launch.c b/src/cc1111/ao_launch.c index 4f0a0c14..76d6d13b 100644 --- a/src/cc1111/ao_launch.c +++ b/src/cc1111/ao_launch.c @@ -17,6 +17,7 @@   */  #include <ao.h> +#include <ao_launch.h>  #include <ao_radio_cmac.h>  __xdata uint16_t ao_launch_ignite; diff --git a/src/cc1111/ao_launch.h b/src/cc1111/ao_launch.h new file mode 100644 index 00000000..966b5cea --- /dev/null +++ b/src/cc1111/ao_launch.h @@ -0,0 +1,44 @@ +/* + * Copyright © 2017 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef _AO_LAUNCH_H_ +#define _AO_LAUNCH_H_ +/* ao_launch.c */ + +struct ao_launch_command { +	uint16_t	tick; +	uint16_t	serial; +	uint8_t		cmd; +	uint8_t		channel; +	uint16_t	unused; +}; + +#define AO_LAUNCH_QUERY		1 + +struct ao_launch_query { +	uint16_t	tick; +	uint16_t	serial; +	uint8_t		channel; +	uint8_t		valid; +	uint8_t		arm_status; +	uint8_t		igniter_status; +}; + +#define AO_LAUNCH_ARM		2 +#define AO_LAUNCH_FIRE		3 + +void +ao_launch_init(void); + +#endif /* _AO_LAUNCH_H_ */ diff --git a/src/cc1111/ao_timer.c b/src/cc1111/ao_timer.c index 0acef562..a3d454da 100644 --- a/src/cc1111/ao_timer.c +++ b/src/cc1111/ao_timer.c @@ -62,7 +62,7 @@ ao_timer_init(void)  	/* NOTE:  This uses a timer only present on cc1111 architecture. */  	/* disable timer 1 */ -	T1CTL = 0; +/*	T1CTL = 0; */  	/* set the sample rate */  	T1CC0H = T1_SAMPLE_TIME >> 8; diff --git a/src/chaoskey-v1.0/.gitignore b/src/chaoskey-v1.0/.gitignore index b0adba26..9fd59154 100644 --- a/src/chaoskey-v1.0/.gitignore +++ b/src/chaoskey-v1.0/.gitignore @@ -1,2 +1,3 @@  ao_product.h  chaoskey-* +*.cab diff --git a/src/chaoskey-v1.0/Makefile b/src/chaoskey-v1.0/Makefile index d9944a12..f2c168ba 100644 --- a/src/chaoskey-v1.0/Makefile +++ b/src/chaoskey-v1.0/Makefile @@ -14,6 +14,7 @@ INC = \  	ao_task.h \  	ao_adc_fast.h \  	ao_power.h \ +	ao_crc.h \  	stm32f0.h  # @@ -38,6 +39,8 @@ ALTOS_SRC = \  	ao_gpio.c \  	ao_product.c +VENDOR=AltusMetrum +PROJECT_NAME=ChaosKey  PRODUCT=ChaosKey-hw-1.0-sw-$(VERSION)  PRODUCT_DEF=-DCHAOSKEY_V_1_0  IDVENDOR=0x1d50 @@ -48,6 +51,7 @@ CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -g -Os  PROGNAME=chaoskey-v1.0  PROG=$(PROGNAME)-$(VERSION).elf  HEX=$(PROGNAME)-$(VERSION).ihx +METAINFO=org.altusmetrum.ChaosKey.metainfo.xml  SRC=$(ALTOS_SRC) ao_chaoskey.c  OBJ=$(SRC:.c=.o) @@ -62,11 +66,20 @@ ao_product.h: ao-make-product.5c ../Version  $(OBJ): $(INC) +%.cab: $(PROG) $(HEX) $(METAINFO) +	gcab --create --nopath $@ $(PROG) $(HEX) $(METAINFO) + +cab: $(VENDOR)-$(PROJECT_NAME)-$(VERSION).cab + +check: $(METAINFO) +	appstream-util validate-relax $(METAINFO) +  distclean:	clean  clean:  	rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx  	rm -f ao_product.h +	rm -f *.cab  install: diff --git a/src/chaoskey-v1.0/chaoskey-connector.svg b/src/chaoskey-v1.0/chaoskey-connector.svg new file mode 100644 index 00000000..671a46bd --- /dev/null +++ b/src/chaoskey-v1.0/chaoskey-connector.svg @@ -0,0 +1,274 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg +   xmlns:dc="http://purl.org/dc/elements/1.1/" +   xmlns:cc="http://creativecommons.org/ns#" +   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" +   xmlns:svg="http://www.w3.org/2000/svg" +   xmlns="http://www.w3.org/2000/svg" +   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" +   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" +   id="svg7384" +   sodipodi:docname="chaoskey.svg" +   version="1.1" +   inkscape:version="0.92pre3 r" +   height="225" +   width="400" +   viewBox="0 0 400 225"> +  <metadata +     id="metadata90"> +    <rdf:RDF> +      <cc:Work +         rdf:about=""> +        <dc:format>image/svg+xml</dc:format> +        <dc:type +           rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> +        <dc:title>Gnome Symbolic Icon Theme</dc:title> +      </cc:Work> +    </rdf:RDF> +  </metadata> +  <sodipodi:namedview +     inkscape:cy="43.99517" +     pagecolor="#e5e6e4" +     borderopacity="1" +     showborder="true" +     inkscape:bbox-paths="false" +     guidetolerance="10" +     inkscape:object-paths="false" +     inkscape:window-width="2560" +     showguides="true" +     inkscape:object-nodes="true" +     inkscape:snap-bbox="true" +     inkscape:pageshadow="2" +     inkscape:guide-bbox="true" +     inkscape:snap-nodes="false" +     bordercolor="#666666" +     objecttolerance="10" +     id="namedview88" +     showgrid="false" +     inkscape:window-maximized="1" +     inkscape:window-x="2560" +     inkscape:snap-global="true" +     inkscape:window-y="0" +     gridtolerance="10" +     inkscape:window-height="1403" +     inkscape:snap-others="false" +     inkscape:snap-to-guides="true" +     inkscape:current-layer="g9377" +     inkscape:snap-bbox-midpoints="false" +     inkscape:zoom="5.6568542" +     inkscape:cx="79.698472" +     inkscape:snap-grids="true" +     inkscape:pageopacity="1" +     inkscape:showpageshadow="false"> +    <inkscape:grid +       spacingx="1px" +       spacingy="1px" +       id="grid4866" +       empspacing="2" +       enabled="true" +       type="xygrid" +       snapvisiblegridlinesonly="true" +       visible="true" /> +  </sodipodi:namedview> +  <title +     id="title9167">Gnome Symbolic Icon Theme</title> +  <defs +     id="defs7386" /> +  <g +     inkscape:label="figures" +     transform="translate(-569.10098,-638)" +     inkscape:groupmode="layer" +     id="layer12" +     style="display:inline"> +    <g +       id="g9377" +       transform="translate(6,740)"> +      <path +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#d3d3ce;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" +         d="m 643.97547,-41.91406 c -6.36396,0 -12.97215,4.683215 -12.97215,12.019445 v 70.902784 9.335743 c 0,7.247844 4.39329,11.492028 10.40889,11.492028 h 109.67315 v -0.043 H 898.3666 v -5.457 -86.88477 -5.45703 H 751.08536 v -1.3125 -4.5957 z m 143.71145,20.37304 c 6.09267,0 11.17907,4.22094 12.44336,9.85938 -1.26429,5.63804 -6.35069,9.85742 -12.44336,9.85742 -6.09267,0 -11.17752,-4.21938 -12.44141,-9.85742 1.26389,-5.63844 6.34874,-9.85938 12.44141,-9.85938 z m 0,50.5918 c 6.09267,-10e-6 11.17907,4.22094 12.44336,9.85938 -1.26429,5.63804 -6.35069,9.85742 -12.44336,9.85742 -6.09267,0 -11.17752,-4.21938 -12.44141,-9.85742 1.26389,-5.63844 6.34874,-9.85939 12.44141,-9.85938 z" +         id="path9437" +         inkscape:connector-curvature="0" +         sodipodi:nodetypes="sccsscccccccccsscscsccscc" /> +      <path +         inkscape:connector-curvature="0" +         id="path9406" +         d="m 749.75794,-30.548211 v 92.340426 h 148.60837 v -92.340426 z m 37.92955,9.007314 c 7.04304,-10e-7 12.75289,5.635711 12.75289,12.5873068 0,6.9515972 -5.70985,12.586021 -12.75289,12.586021 -7.04304,0 -12.75289,-5.6344238 -12.75289,-12.586021 0,-6.9515958 5.70985,-12.5873078 12.75289,-12.5873068 z m 0,50.591426 c 7.04304,-7e-6 12.75289,5.635708 12.75289,12.587306 0,6.951598 -5.70985,12.58602 -12.75289,12.58602 -7.04304,0 -12.75289,-5.634422 -12.75289,-12.58602 0,-6.951598 5.70985,-12.587313 12.75289,-12.587306 z" +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#d3d3ce;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> +      <path +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" +         d="m 749.75794,-36.005319 v 92.340426 h 148.60837 v -92.340426 z m 37.92955,9.007314 c 7.04304,-1e-6 12.75289,5.635711 12.75289,12.587308 0,6.9515972 -5.70985,12.5860213 -12.75289,12.5860213 -7.04304,0 -12.75289,-5.6344241 -12.75289,-12.5860213 0,-6.951597 5.70985,-12.587309 12.75289,-12.587308 z m 0,50.591426 c 7.04304,-7e-6 12.75289,5.635708 12.75289,12.587306 0,6.951598 -5.70985,12.58602 -12.75289,12.58602 -7.04304,0 -12.75289,-5.634422 -12.75289,-12.58602 0,-6.951598 5.70985,-12.587313 12.75289,-12.587306 z" +         id="rect9282" +         inkscape:connector-curvature="0" /> +      <rect +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#cc0000;fill-opacity:1;fill-rule:nonzero;stroke:#a40000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" +         id="rect9374" +         width="12.092357" +         height="12.060186" +         x="829.53729" +         y="-29.215614" +         rx="0" +         ry="0" /> +      <ellipse +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#a40000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" +         id="path9300" +         cx="835.67212" +         cy="-23.143618" +         rx="3.6488662" +         ry="3.6276596" /> +      <ellipse +         cy="-11.930851" +         cx="835.67212" +         id="circle9316" +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" +         rx="3.6488662" +         ry="3.6276596" /> +      <ellipse +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" +         id="circle9318" +         cx="835.67212" +         cy="-1.3776593" +         rx="3.6488662" +         ry="3.6276596" /> +      <ellipse +         cy="9.1755333" +         cx="835.67212" +         id="circle9320" +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" +         rx="3.6488662" +         ry="3.6276596" /> +      <ellipse +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#cc0000;fill-opacity:1;fill-rule:nonzero;stroke:#a40000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" +         id="circle9322" +         cx="835.67212" +         cy="19.728724" +         rx="3.6488662" +         ry="3.6276596" /> +      <rect +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" +         id="rect9339" +         width="9.288023" +         height="16.489361" +         x="791.55402" +         y="4.888298" /> +      <rect +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#d3d3ce;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" +         id="rect9341" +         width="18.576046" +         height="11.87234" +         x="805.48608" +         y="-24.132978" /> +      <rect +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" +         id="rect9343" +         width="17.249186" +         height="7.9148936" +         x="750.42133" +         y="-18.835106" /> +      <rect +         y="-1.6861706" +         x="750.42133" +         height="7.9148936" +         width="17.249186" +         id="rect9345" +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> +      <rect +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" +         id="rect9347" +         width="17.249186" +         height="7.9148936" +         x="750.42133" +         y="15.462767" /> +      <path +         inkscape:connector-curvature="0" +         id="path9404" +         d="m 634.00914,-35.108991 -3.0052,84.392953 c 0,8.662058 3.50963,12.551145 11.82333,12.551145 l 108.25753,0 V -37.3187 Z" +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#d3d3ce;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:2;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" +         sodipodi:nodetypes="cccccc" /> +      <rect +         y="32.611702" +         x="750.42133" +         height="7.9148936" +         width="17.249186" +         id="rect9349" +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> +      <rect +         y="-24.132978" +         x="853.25305" +         height="38.255318" +         width="37.815521" +         id="rect9351" +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#d3d3ce;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> +      <rect +         y="34.569149" +         x="869.83881" +         height="11.87234" +         width="18.576046" +         id="rect9353" +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#d3d3ce;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> +      <rect +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#d3d3ce;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" +         id="rect9355" +         width="13.268604" +         height="19.787233" +         x="849.93591" +         y="26.654255" /> +      <rect +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#d3d3ce;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" +         id="rect9359" +         width="18.576046" +         height="15.829787" +         x="808.80322" +         y="30.611702" /> +      <path +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:2;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" +         d="m 631.00394,-29.80569 v 69.648156 c 0,6.815994 3.28909,11.242641 9.52371,11.242641 H 751.0848 V -41.914894 H 645.03698 c -7.86656,0 -14.03304,4.772971 -14.03304,12.109204 z m 35.80579,-0.962137 h 11.98062 c 1.47016,0 2.65372,1.176681 2.65372,2.638298 v 17.280335 c 0,1.4616169 -1.18356,2.6382978 -2.65372,2.6382978 h -11.98062 c -1.47016,0 -2.65372,-1.1766809 -2.65372,-2.6382978 v -17.280335 c 0,-1.461617 1.18356,-2.638298 2.65372,-2.638298 z m 0,46.829786 h 11.98062 c 1.47016,0 2.65372,1.176681 2.65372,2.638298 v 17.280337 c 0,1.461617 -1.18356,2.638298 -2.65372,2.638298 h -11.98062 c -1.47016,0 -2.65372,-1.176681 -2.65372,-2.638298 V 18.700257 c 0,-1.461617 1.18356,-2.638298 2.65372,-2.638298 z" +         id="rect9362" +         inkscape:connector-curvature="0" +         sodipodi:nodetypes="cccccccssssssssssssssssss" /> +      <ellipse +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" +         id="path9364" +         cx="738.81134" +         cy="5.2446804" +         rx="4.3122964" +         ry="4.2872338" /> +      <rect +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" +         id="rect9408" +         width="37.815521" +         height="38.255318" +         x="853.25305" +         y="-28.132978" /> +      <rect +         y="26.611702" +         x="808.80322" +         height="15.829787" +         width="18.576046" +         id="rect9410" +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> +      <rect +         y="-28.132978" +         x="805.48608" +         height="11.87234" +         width="18.576046" +         id="rect9412" +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> +      <rect +         y="22.654255" +         x="849.93591" +         height="19.787233" +         width="13.268604" +         id="rect9414" +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> +      <rect +         style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" +         id="rect9416" +         width="18.576046" +         height="11.87234" +         x="869.83881" +         y="30.569149" /> +    </g> +  </g> +</svg> diff --git a/src/chaoskey-v1.0/org.altusmetrum.ChaosKey.metainfo.xml.in b/src/chaoskey-v1.0/org.altusmetrum.ChaosKey.metainfo.xml.in new file mode 100644 index 00000000..6e391878 --- /dev/null +++ b/src/chaoskey-v1.0/org.altusmetrum.ChaosKey.metainfo.xml.in @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright 2017 Richard Hughes <richard@hughsie.com> --> +<component type="firmware"> +  <id>org.altusmetrum.ChaosKey.firmware</id> +  <name>ChaosKey</name> +  <summary>Firmware for the Altus Metrum ChaosKey</summary> +  <description> +    <p> +      Updating the firmware on your ChaosKey device improves performance and adds +      new features. +    </p> +  </description> +  <provides> +    <!-- USB\VID_1D50&PID_60C6 --> +    <firmware type="flashed">b62500d7-c981-595b-a798-eb6cf4d4942b</firmware> +  </provides> +  <url type="homepage">https://chaoskey.org/</url> +  <metadata_license>CC-BY-4.0</metadata_license> +  <project_license>GPL-2.0</project_license> +  <developer_name>AltusMetrum</developer_name> +  <releases> +    <release urgency="medium" version="@VERSION@" date="@RELEASE_DATE@"> +      <checksum filename="chaoskey-v1.0-@VERSION@.ihx" target="content"/> +      <description> +        <p> +          FIXME before release. +        </p> +      </description> +    </release> +    <release urgency="medium" version="1.6.7" date="2017-01-01"> +      <checksum filename="chaoskey-v1.0-1.6.7.ihx" target="content"/> +      <description> +        <p> +          Change the ADC clock speed to eliminate sampling problems which +          cleans up the chaoskey raw data. +        </p> +      </description> +    </release> +  </releases> +  <screenshots> +    <screenshot type="default"> +      <image type="source">https://chaoskey.org/chaoskey-connector.svg</image> +      <caption>Remove the plastic cover, then connect pins 1 and 5 whilst inserting into a USB socket.</caption> +    </screenshot> +  </screenshots> +</component> diff --git a/src/cortexelf-v1/Makefile b/src/cortexelf-v1/Makefile new file mode 100644 index 00000000..8cc6ce31 --- /dev/null +++ b/src/cortexelf-v1/Makefile @@ -0,0 +1,137 @@ +# +# AltOS build +# +# + +include ../stm/Makefile.defs +LDFLAGS=-L../stm -Wl,-Tcortexelf.ld + +INC = \ +	ao.h \ +	ao_arch.h \ +	ao_arch_funcs.h \ +	ao_boot.h \ +	ao_pins.h \ +	ao_kalman.h \ +	ao_product.h \ +	ao_profile.h \ +	ao_task.h \ +	math.h \ +	ao_mpu.h \ +	stm32l.h \ +	math.h \ +	ao_vga.h \ +	ao_draw.h \ +	ao_draw_int.h \ +	ao_font.h \ +	ao_ps2.h \ +	ao_lisp.h \ +	ao_lisp_const.h \ +	ao_lisp_os.h \ +	ao_flip_bits.h \ +	Makefile + +#PROFILE=ao_profile.c +#PROFILE_DEF=-DAO_PROFILE=1 + +#STACK_GUARD=ao_mpu_stm.c +#STACK_GUARD_DEF=-DHAS_STACK_GUARD=1 + + +ALTOS_SRC = \ +	ao_boot_chain.c \ +	ao_interrupt.c \ +	ao_product.c \ +	ao_romconfig.c \ +	ao_cmd.c \ +	ao_config.c \ +	ao_task.c \ +	ao_stdio.c \ +	ao_panic.c \ +	ao_timer.c \ +	ao_mutex.c \ +	ao_serial_stm.c \ +	ao_dma_stm.c \ +	ao_spi_stm.c \ +	ao_usb_stm.c \ +	ao_exti_stm.c \ +	ao_i2c_stm.c \ +	ao_as1107.c \ +	ao_matrix.c \ +	ao_vga.c \ +	ao_blt.c \ +	ao_copy.c \ +	ao_rect.c \ +	ao_text.c \ +	ao_line.c \ +	ao_ps2.c \ +	ao_console.c \ +	ao_sdcard.c \ +	ao_bufio.c \ +	ao_fat.c \ +	ao_flash_stm.c \ +	ao_button.c \ +	ao_event.c \ +	ao_1802.c \ +	ao_hex.c \ +	ao_lisp_lex.c \ +	ao_lisp_mem.c \ +	ao_lisp_cons.c \ +	ao_lisp_eval.c \ +	ao_lisp_string.c \ +	ao_lisp_atom.c \ +	ao_lisp_int.c \ +	ao_lisp_poly.c \ +	ao_lisp_builtin.c \ +	ao_lisp_read.c \ +	ao_lisp_rep.c \ +	ao_lisp_frame.c \ +	ao_lisp_error.c \ +	ao_lisp_lambda.c \ +	ao_lisp_save.c \ +	ao_lisp_stack.c \ +	ao_lisp_os_save.c \ +	$(PROFILE) \ +	$(SAMPLE_PROFILE) \ +	$(STACK_GUARD) + +PRODUCT=CortexELF-v1 +PRODUCT_DEF=-DCORTEXELF +IDPRODUCT=0x000a + +CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g + +PROGNAME=cortexelf-v1 +PROG=$(PROGNAME)-$(VERSION).elf +HEX=$(PROGNAME)-$(VERSION).ihx + +SRC=$(ALTOS_SRC) ao_cortexelf.c +OBJ=$(SRC:.c=.o) + +all:: $(PROG) $(HEX) + +$(PROG): Makefile $(OBJ) cortexelf.ld +	$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) + +../altitude-pa.h: make-altitude-pa +	nickle $< > $@ + +$(OBJ): $(INC) + +ao_product.h: ao-make-product.5c ../Version +	$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean:	clean + +clean:: +	rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx +	rm -f ao_product.h ao_flip_bits.h + +ao_flip_bits.h: ao_flip_bits.5c +	nickle ao_flip_bits.5c > $@ + +include ../lisp/Makefile-lisp + +install: + +uninstall: diff --git a/src/cortexelf-v1/ao_1802.c b/src/cortexelf-v1/ao_1802.c new file mode 100644 index 00000000..9fb36595 --- /dev/null +++ b/src/cortexelf-v1/ao_1802.c @@ -0,0 +1,328 @@ +/* + * Copyright © 2017 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <ao.h> +#include <ao_flip_bits.h> +#include <ao_1802.h> +#include <ao_exti.h> + +/* Decoded address driven by TPA/TPB signals */ +uint16_t	ADDRESS; + +/* Decoded data, driven by TPB signal */ +uint8_t		DATA; + +/* Mux control */ +#define _MUX_1802		0 +#define _MUX_STM		1 + +uint8_t		MUX_CONTROL; + +/* Signals muxed between 1802 and STM */ +uint8_t +MRD(void) { +	return ao_gpio_get(MRD_PORT, MRD_BIT, MRD_PIN); +} + +void +MRD_set(uint8_t value) { +	ao_gpio_set(MRD_PORT, MRD_BIT, MRD_PIN, value); +} + +uint8_t +MWR(void) { +	return ao_gpio_get(MWR_PORT, MWR_BIT, MWR_PIN); +} + +void +MWR_set(uint8_t value) { +	ao_gpio_set(MWR_PORT, MWR_BIT, MWR_PIN, value); +} + +static void +TPA_rising(void) +{ +	ADDRESS = (ADDRESS & 0x00ff) | ((uint16_t) MA() << 8); +	ao_wakeup(&ADDRESS); +} + +uint8_t +TPA(void) { +	return ao_gpio_get(TPA_PORT, TPA_BIT, TPA_PIN); +} + +void +TPA_set(uint8_t tpa) { +	ao_gpio_set(TPA_PORT, TPA_BIT, TPA_PIN, tpa); +	if (tpa) +		TPA_rising(); +} + +static void +TPB_rising(void) +{ +	ADDRESS = (ADDRESS & 0xff00) | MA(); +	if (MWR() == 0 || MRD() == 0) +		DATA = BUS(); +	ao_wakeup(&ADDRESS); +} + +static void +TPB_falling(void) +{ +} + +uint8_t +TPB(void) { +	return ao_gpio_get(TPB_PORT, TPB_BIT, TPB_PIN); +} + +void +TPB_set(uint8_t tpb) { +	ao_gpio_set(TPB_PORT, TPB_BIT, TPB_PIN, tpb); +	if (tpb) +		TPB_rising(); +	else +		TPB_falling(); +} + +uint8_t +MA(void) { +	return (ao_gpio_get_all(MA_PORT) >> MA_SHIFT) & MA_MASK; +} + +void +MA_set(uint8_t ma) { +	ao_gpio_set_mask(MA_PORT, ((uint16_t) ma) << MA_SHIFT, MA_MASK << MA_SHIFT); +} + +/* Tri-state data bus */ + +uint8_t +BUS(void) { +	return ao_flip_bits_8[(ao_gpio_get_all(BUS_PORT) >> BUS_SHIFT) & BUS_MASK]; +} + +void +BUS_set(uint8_t bus) { +	ao_gpio_set_mask(BUS_PORT, ao_flip_bits_8[bus] << BUS_SHIFT, BUS_MASK << BUS_SHIFT); +} + +void +BUS_stm(void) +{ +	ao_set_output_mask(BUS_PORT, BUS_MASK << BUS_SHIFT); +} + +void +BUS_1802(void) +{ +	ao_set_input_mask(BUS_PORT, BUS_MASK << BUS_SHIFT); +} + +/* Pins controlled by 1802 */ +uint8_t +SC(void) { +	return ao_flip_bits_2[(ao_gpio_get_all(SC_PORT) >> SC_SHIFT) & SC_MASK]; +} + +uint8_t +Q(void) { +	return ao_gpio_get(Q_PORT, Q_BIT, Q_PIN); +} + +uint8_t +N(void) { +	return (ao_gpio_get_all(N_PORT) >> N_SHIFT) & N_MASK; +} + +/* Pins controlled by STM */ +uint8_t +EF(void) { +	return (ao_gpio_get_all(EF_PORT) >> EF_SHIFT) & EF_MASK; +} + +void +EF_set(uint8_t ef) { +	ao_gpio_set_mask(EF_PORT, ef << EF_SHIFT, EF_MASK << EF_SHIFT); +} + +uint8_t +DMA_IN(void) { +	return ao_gpio_get(DMA_IN_PORT, DMA_IN_BIT, DMA_IN_PIN); +} + +void +DMA_IN_set(uint8_t dma_in) { +	ao_gpio_set(DMA_IN_PORT, DMA_IN_BIT, DMA_IN_PIN, dma_in); +} + +uint8_t +DMA_OUT(void) { +	return ao_gpio_get(DMA_OUT_PORT, DMA_OUT_BIT, DMA_OUT_PIN); +} + +void +DMA_OUT_set(uint8_t dma_out) { +	ao_gpio_set(DMA_OUT_PORT, DMA_OUT_BIT, DMA_OUT_PIN, dma_out); +} + +uint8_t +INT(void) { +	return ao_gpio_get(INT_PORT, INT_BIT, INT_PIN); +} + +void +INT_set(uint8_t dma_out) { +	ao_gpio_set(INT_PORT, INT_BIT, INT_PIN, dma_out); +} + +uint8_t +CLEAR(void) { +	return ao_gpio_get(CLEAR_PORT, CLEAR_BIT, CLEAR_PIN); +} + +void +CLEAR_set(uint8_t dma_out) { +	ao_gpio_set(CLEAR_PORT, CLEAR_BIT, CLEAR_PIN, dma_out); +} + +uint8_t +WAIT(void) { +	return ao_gpio_get(WAIT_PORT, WAIT_BIT, WAIT_PIN); +} + +void +WAIT_set(uint8_t dma_out) { +	ao_gpio_set(WAIT_PORT, WAIT_BIT, WAIT_PIN, dma_out); +} + +void +tpb_isr(void) { +	/* Latch low address and data on rising edge of TPB */ +	if (TPB()) +		TPB_rising(); +	else +		TPB_falling(); +} + +void +tpa_isr(void) { +	/* Latch high address on rising edge of TPA */ +	if (TPA()) +		TPA_rising(); +} + +#define ao_1802_in(port, bit, mode) do {		\ +		ao_gpio_set_mode(port, bit, mode);	\ +		ao_set_input(port, bit);		\ +	} while (0) + +#define ao_1802_in_isr(port, bit, mode) do {		\ +		ao_gpio_set_mode(port, bit, mode);	\ +		ao_set_input(port, bit);		\ +		ao_exti_enable(port, bit);		\ +	} while (0) + +#define ao_1802_out_isr(port, bit) do { \ +		ao_exti_disable(port, bit); \ +		ao_set_output(port, bit); \ +	} while (0) + +void +MUX_1802(void) +{ +	if (MUX_CONTROL != _MUX_1802) { +		/* Set pins to input, but pulled to idle value */ +		ao_1802_in(MRD_PORT, MRD_BIT, AO_EXTI_MODE_PULL_UP); +		ao_1802_in(MWR_PORT, MWR_BIT, AO_EXTI_MODE_PULL_UP); +		ao_1802_in_isr(TPB_PORT, TPB_BIT, AO_EXTI_MODE_PULL_DOWN); +		ao_1802_in_isr(TPA_PORT, TPA_BIT, AO_EXTI_MODE_PULL_DOWN); +		ao_set_input_mask(MA_PORT, MA_MASK << MA_SHIFT); + +		ao_gpio_set(MUX_PORT, MUX_BIT, MUX_PIN, 0); + +		/* Now change the pins to eliminate the pull up/down */ +		ao_gpio_set_mode(MRD_PORT, MRD_BIT, 0); +		ao_gpio_set_mode(MWR_PORT, MWR_BIT, 0); +		ao_gpio_set_mode(TPB_PORT, TPB_BIT, 0); +		ao_gpio_set_mode(TPA_PORT, TPA_BIT, 0); + +		MUX_CONTROL = _MUX_1802; +	} +} + +void +MUX_stm(void) +{ +	if (MUX_CONTROL != _MUX_STM) { +		/* Set the pins back to pull to the idle value */ +		ao_gpio_set_mode(MRD_PORT, MRD_BIT, AO_EXTI_MODE_PULL_UP); +		ao_gpio_set_mode(MWR_PORT, MWR_BIT, AO_EXTI_MODE_PULL_UP); +		ao_gpio_set_mode(TPB_PORT, TPB_BIT, AO_EXTI_MODE_PULL_DOWN); +		ao_gpio_set_mode(TPA_PORT, TPA_BIT, AO_EXTI_MODE_PULL_DOWN); + +		ao_gpio_set(MUX_PORT, MUX_BIT, MUX_PIN, 1); + +		/* Now set the pins as output, driven to the idle value */ +		ao_set_output(MRD_PORT, MRD_BIT, MRD_PIN, 1); +		ao_set_output(MWR_PORT, MWR_BIT, MWR_PIN, 1); +		ao_set_output(TPB_PORT, TPB_BIT, TPB_PIN, 0); +		ao_set_output(TPA_PORT, TPA_BIT, TPA_PIN, 0); +		ao_set_output_mask(MA_PORT, MA_MASK << MA_SHIFT); +		MUX_CONTROL = _MUX_STM; +	} +} + +void +ao_1802_init(void) +{ +	/* Multiplexed signals*/ + +	/* active low signals */ +	ao_enable_input(MRD_PORT, MRD_BIT, AO_EXTI_MODE_PULL_UP); +	ao_enable_input(MWR_PORT, MWR_BIT, AO_EXTI_MODE_PULL_UP); + +	/* active high signals with interrupts */ +	ao_exti_setup(TPA_PORT, TPA_BIT, +		      AO_EXTI_MODE_PULL_DOWN | AO_EXTI_MODE_RISING | AO_EXTI_MODE_FALLING, +		      tpa_isr); +	ao_exti_setup(TPB_PORT, TPB_BIT, +		      AO_EXTI_MODE_PULL_DOWN | AO_EXTI_MODE_RISING | AO_EXTI_MODE_FALLING, +		      tpb_isr); + +	/* multiplexed address bus */ +	ao_enable_input_mask(MA_PORT, MA_MASK << MA_SHIFT, 0); + +	/* Data bus */ + +	ao_enable_input_mask(BUS_PORT, BUS_MASK << BUS_SHIFT, 0); + +	/* Pins controlled by 1802 */ +	ao_enable_input_mask(SC_PORT, SC_MASK << SC_SHIFT, 0); +	ao_enable_input(Q_PORT, Q_BIT, 0); +	ao_enable_input_mask(N_PORT, N_MASK << N_SHIFT, 0); + +	/* Pins controlled by STM */ +	ao_enable_output_mask(EF_PORT, 0, EF_MASK << EF_SHIFT); +	ao_enable_output(DMA_IN_PORT, DMA_IN_BIT, DMA_IN_PIN, 1); +	ao_enable_output(DMA_OUT_PORT, DMA_OUT_BIT, DMA_OUT_PIN, 1); +	ao_enable_output(INT_PORT, INT_BIT, INT_PIN, 1); +	ao_enable_output(CLEAR_PORT, CLEAR_BIT, CLEAR_PIN, 1); +	ao_enable_output(WAIT_PORT, WAIT_BIT, WAIT_PIN, 1); + +	/* Force configuration to STM so that MUX_1802 will do something */ +	MUX_CONTROL = _MUX_STM; +	MUX_1802(); +} diff --git a/src/cortexelf-v1/ao_1802.h b/src/cortexelf-v1/ao_1802.h new file mode 100644 index 00000000..5ea89fee --- /dev/null +++ b/src/cortexelf-v1/ao_1802.h @@ -0,0 +1,129 @@ +/* + * Copyright © 2017 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef _AO_1802_H_ +#define _AO_1802_H_ + +/* Decoded address driven by TPA/TPB signals */ +extern uint16_t		ADDRESS; + +/* Decoded data, driven by TPB signal */ +extern uint8_t		DATA; + +uint8_t +MRD(void); + +void +MRD_set(uint8_t value); + +uint8_t +MWR(void); + +void +MWR_set(uint8_t value); + +uint8_t +TPA(void); + +void +TPA_set(uint8_t tpa); + +uint8_t +TPB(void); + +void +TPB_set(uint8_t tpb); + +uint8_t +MA(void); + +void +MA_set(uint8_t ma); + +/* Tri-state data bus */ + +uint8_t +BUS(void); + +void +BUS_set(uint8_t bus); + +void +BUS_stm(void); + +void +BUS_1802(void); + +/* Pins controlled by 1802 */ +uint8_t +SC(void); + +uint8_t +Q(void); + +uint8_t +N(void); + +/* Pins controlled by STM */ +uint8_t +EF(void); + +void +EF_set(uint8_t ef); + +uint8_t +DMA_IN(void); + +void +DMA_IN_set(uint8_t dma_in); + +uint8_t +DMA_OUT(void); + +void +DMA_OUT_set(uint8_t dma_out); + +uint8_t +INT(void); + +void +INT_set(uint8_t dma_out); + +uint8_t +CLEAR(void); + +void +CLEAR_set(uint8_t dma_out); + +uint8_t +WAIT(void); + +void +WAIT_set(uint8_t dma_out); + +#define SC_FETCH	0 +#define SC_EXECUTE	1 +#define SC_DMA		2 +#define SC_INTERRUPT	3 + +void +MUX_1802(void); + +void +MUX_stm(void); + +void +ao_1802_init(void); + +#endif /* _AO_1802_H_ */ diff --git a/src/cortexelf-v1/ao_cortexelf.c b/src/cortexelf-v1/ao_cortexelf.c new file mode 100644 index 00000000..61a9d219 --- /dev/null +++ b/src/cortexelf-v1/ao_cortexelf.c @@ -0,0 +1,291 @@ +/* + * Copyright © 2011 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <ao.h> +#include <ao_exti.h> +#include <ao_profile.h> +#if HAS_STACK_GUARD +#include <ao_mpu.h> +#endif +#include <ao_ps2.h> +#include <ao_vga.h> +#include <ao_console.h> +#include <ao_sdcard.h> +#include <ao_fat.h> +#include <ao_lisp.h> +#include <ao_button.h> +#include <ao_event.h> +#include <ao_as1107.h> +#include <ao_hex.h> +#include <ao_1802.h> + +struct ao_task ball_task; + +#define BALL_WIDTH	5 +#define BALL_HEIGHT	5 + +static int	ball_x; +static int	ball_y; +static int	ball_dx, ball_dy; + +uint8_t		ball_enable; + +void +ao_ball(void) +{ +	ball_dx = 1; +	ball_dy = 1; +	ball_x = 0; +	ball_y = 0; +	for (;;) { +		while (!ball_enable) +			ao_sleep(&ball_enable); +		for (;;) { +			ao_line(&ao_vga_bitmap, +				-100, -100, ball_x*2, ball_y*2, +				1, AO_XOR); +			ao_text(&ao_vga_bitmap, +				ball_x, ball_y - 10, +				"Hello, Bdale!", +				1, AO_XOR); +			ao_rect(&ao_vga_bitmap, +				ball_x, ball_y, +				BALL_WIDTH, +				BALL_HEIGHT, +				1, +				AO_XOR); +			ao_delay(AO_MS_TO_TICKS(10)); +			ao_rect(&ao_vga_bitmap, +				ball_x, ball_y, +				BALL_WIDTH, +				BALL_HEIGHT, +				1, +				AO_XOR); +			ao_text(&ao_vga_bitmap, +				ball_x, ball_y - 10, +				"Hello, Bdale!", +				1, AO_XOR); +			ao_line(&ao_vga_bitmap, +				-100, -100, ball_x*2, ball_y*2, +				1, AO_XOR); +			if (!ball_enable) +				break; +			ball_x += ball_dx; +			ball_y += ball_dy; +			if (ball_x + BALL_WIDTH > AO_VGA_WIDTH) { +				ball_x = AO_VGA_WIDTH - BALL_WIDTH; +				ball_dx = -ball_dx; +			} +			if (ball_x < 0) { +				ball_x = -ball_x; +				ball_dx = -ball_dx; +			} +			if (ball_y + BALL_HEIGHT > AO_VGA_HEIGHT) { +				ball_y = AO_VGA_HEIGHT - BALL_HEIGHT; +				ball_dy = -ball_dy; +			} +			if (ball_y < 0) { +				ball_y = -ball_y; +				ball_dy = -ball_dy; +			} +		} +	} +} + +static void +ao_fb_init(void) +{ +	ao_rect(&ao_vga_bitmap, +		0, 0, AO_VGA_WIDTH, AO_VGA_HEIGHT, +		1, AO_COPY); + +	ao_rect(&ao_vga_bitmap, +		10, 10, 10, 10, +		0, AO_COPY); + +	ao_rect(&ao_vga_bitmap, +		AO_VGA_WIDTH - 20, 10, 10, 10, +		0, AO_COPY); + +	ao_rect(&ao_vga_bitmap, +		10, AO_VGA_HEIGHT - 20, 10, 10, +		0, AO_COPY); + +	ao_rect(&ao_vga_bitmap, +		AO_VGA_WIDTH - 20, AO_VGA_HEIGHT - 20, 10, 10, +		0, AO_COPY); + +	ao_text(&ao_vga_bitmap, +		20, 100, +		"Hello, Bdale!", +		0, AO_COPY); + +	ao_text(&ao_vga_bitmap, +		1, ao_font.ascent, +		"UL", +		0, AO_COPY); + +	ao_text(&ao_vga_bitmap, +		1, AO_VGA_HEIGHT - ao_font.descent, +		"BL", +		0, AO_COPY); +} + +static void +ao_video_toggle(void) +{ +	ao_cmd_decimal(); +	if (ao_cmd_lex_i) +		ao_fb_init(); +	ao_vga_enable(ao_cmd_lex_i); +} + +static void +ao_ball_toggle(void) +{ +	ao_cmd_decimal(); +	ball_enable = ao_cmd_lex_i; +	ao_wakeup(&ball_enable); +} + +static void +ao_ps2_read_keys(void) +{ +	char	c; + +	for (;;) { +		c = ao_ps2_getchar(); +		printf("%02x %c\n", c, ' ' <= c && c < 0x7f ? c : '.'); +		flush(); +		if (c == ' ') +			break; +	} +} + +static void +ao_console_send(void) +{ +	char	c; + +	while ((c = getchar()) != '~') { +		ao_console_putchar(c); +		flush(); +	} +} + +static void lisp_cmd() { +	ao_lisp_read_eval_print(); +} + +static void +ao_serial_blather(void) +{ +	char c; + +	while ((c = getchar()) != '~') { +		ao_serial1_putchar(c); +		ao_serial2_putchar(c); +	} +} + +static void +led_cmd(void) +{ +	uint8_t	start; +	uint8_t value; +	ao_cmd_decimal(); + +	start = ao_cmd_lex_i; +	ao_cmd_hex(); +	value = ao_cmd_lex_i; +	if (ao_cmd_status != ao_cmd_success) +		return; +	ao_as1107_write_8(start, value); +} + +__code struct ao_cmds ao_demo_cmds[] = { +	{ ao_video_toggle, "V\0Toggle video" }, +	{ ao_ball_toggle, "B\0Toggle ball" }, +	{ ao_ps2_read_keys, "K\0Read keys from keyboard" }, +	{ ao_console_send, "C\0Send data to console, end with ~" }, +	{ ao_serial_blather, "S\0Blather on serial ports briefly" }, +	{ lisp_cmd, "l\0Run lisp interpreter" }, +	{ led_cmd, "L start value\0Show value (byte) at digit start" }, +	{ 0, NULL } +}; + +static struct ao_task event_task; + +static void +ao_event_loop(void) +{ +	for (;;) { +		struct ao_event	ev; + +		ao_event_get(&ev); +		printf("type %d uint %d tick %d value %d\n", +		       ev.type, ev.unit, ev.tick, ev.value); +		flush(); +	} +} + +int +main(void) +{ +	ao_clock_init(); + +#if HAS_STACK_GUARD +	ao_mpu_init(); +#endif + +	ao_task_init(); +	ao_serial_init(); +	ao_timer_init(); + +	ao_spi_init(); +	ao_dma_init(); +	ao_exti_init(); + +	ao_sdcard_init(); +	ao_fat_init(); + +	ao_ps2_init(); +	ao_vga_init(); +	ao_console_init(); + +	ao_cmd_init(); + +	ao_usb_init(); + +	ao_button_init(); + +	ao_as1107_init(); +	ao_matrix_init(); +	ao_1802_init(); + +	ao_hex_init(); + +	ao_config_init(); + +	ao_add_task(&ball_task, ao_ball, "ball"); +	ao_add_task(&event_task, ao_event_loop, "events"); +	ao_cmd_register(&ao_demo_cmds[0]); + +	ao_start_scheduler(); +	return 0; +} diff --git a/src/cortexelf-v1/ao_flip_bits.5c b/src/cortexelf-v1/ao_flip_bits.5c new file mode 100644 index 00000000..cd5507cc --- /dev/null +++ b/src/cortexelf-v1/ao_flip_bits.5c @@ -0,0 +1,24 @@ +#!/usr/bin/nickle + +int flip_bits(int a, int n) +{ +	int result = 0; +	for (int pos = 0; pos < n; pos++) +		if ((a & (1 << pos)) != 0) +			result |= (1 << (n - 1 - pos)); +	return result; +} + +void print_flip_bits(string name, int n) { +	printf ("static const uint8_t %s_%d[%d] = {\n", name, n, 1 << n); + +	for (int i = 0; i < 1 << n; i++) { +		printf (" 0x%02x,", flip_bits(i, n)); +		if ((i & 0xf) == 0xf) +			printf("\n"); +	} +	printf("};\n"); +} + +print_flip_bits("ao_flip_bits", 8); +print_flip_bits("ao_flip_bits", 2); diff --git a/src/cortexelf-v1/ao_hex.c b/src/cortexelf-v1/ao_hex.c new file mode 100644 index 00000000..1507407b --- /dev/null +++ b/src/cortexelf-v1/ao_hex.c @@ -0,0 +1,36 @@ +/* + * Copyright © 2017 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <ao.h> +#include "ao_hex.h" +#include "ao_as1107.h" +#include "ao_1802.h" + +static struct ao_task	ao_hex_task; + +static void +ao_hex(void) +{ +	for (;;) { +		ao_as1107_write_16(0, ADDRESS); +		ao_as1107_write_8(6, DATA); +		ao_sleep(&ADDRESS); +	} +} + +void +ao_hex_init(void) +{ +	ao_add_task(&ao_hex_task, ao_hex, "hex"); +} diff --git a/src/cortexelf-v1/ao_hex.h b/src/cortexelf-v1/ao_hex.h new file mode 100644 index 00000000..674c1eee --- /dev/null +++ b/src/cortexelf-v1/ao_hex.h @@ -0,0 +1,21 @@ +/* + * Copyright © 2017 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef _AO_HEX_H_ +#define _AO_HEX_H_ + +void +ao_hex_init(void); + +#endif /* _AO_HEX_H_ */ diff --git a/src/cortexelf-v1/ao_lisp_os.h b/src/cortexelf-v1/ao_lisp_os.h new file mode 100644 index 00000000..d0c1f7b7 --- /dev/null +++ b/src/cortexelf-v1/ao_lisp_os.h @@ -0,0 +1,65 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_LISP_OS_H_ +#define _AO_LISP_OS_H_ + +#include "ao.h" + +#define AO_LISP_POOL_TOTAL		16384 +#define AO_LISP_SAVE			1 + +static inline int +ao_lisp_getc() { +	static uint8_t	at_eol; +	int c; + +	if (at_eol) { +		ao_cmd_readline(); +		at_eol = 0; +	} +	c = ao_cmd_lex(); +	if (c == '\n') +		at_eol = 1; +	return c; +} + +static inline void +ao_lisp_os_flush(void) +{ +	flush(); +} + +static inline void +ao_lisp_abort(void) +{ +	ao_panic(1); +} + +static inline void +ao_lisp_os_led(int led) +{ +	(void) led; +} + +static inline void +ao_lisp_os_delay(int delay) +{ +	ao_delay(AO_MS_TO_TICKS(delay)); +} + +#endif diff --git a/src/cortexelf-v1/ao_lisp_os_save.c b/src/cortexelf-v1/ao_lisp_os_save.c new file mode 100644 index 00000000..7c853990 --- /dev/null +++ b/src/cortexelf-v1/ao_lisp_os_save.c @@ -0,0 +1,53 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <ao.h> +#include <ao_lisp.h> +#include <ao_flash.h> + +extern uint8_t	__flash__[]; + +/* saved variables to rebuild the heap + +   ao_lisp_atoms +   ao_lisp_frame_global + */ + +int +ao_lisp_os_save(void) +{ +	int i; + +	for (i = 0; i < AO_LISP_POOL_TOTAL; i += 256) { +		uint32_t	*dst = (uint32_t *) (void *) &__flash__[i]; +		uint32_t	*src = (uint32_t *) (void *) &ao_lisp_pool[i]; + +		ao_flash_page(dst, src); +	} +	return 1; +} + +int +ao_lisp_os_restore_save(struct ao_lisp_os_save *save, int offset) +{ +	memcpy(save, &__flash__[offset], sizeof (struct ao_lisp_os_save)); +	return 1; +} + +int +ao_lisp_os_restore(void) +{ +	memcpy(ao_lisp_pool, __flash__, AO_LISP_POOL_TOTAL); +	return 1; +} diff --git a/src/cortexelf-v1/ao_pins.h b/src/cortexelf-v1/ao_pins.h new file mode 100644 index 00000000..258ffe31 --- /dev/null +++ b/src/cortexelf-v1/ao_pins.h @@ -0,0 +1,265 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#define HAS_TASK_QUEUE		1 + +/* 8MHz High speed external crystal */ +#define AO_HSE			8000000 + +/* PLLVCO = 96MHz (so that USB will work) */ +#define AO_PLLMUL		12 +#define AO_RCC_CFGR_PLLMUL	(STM_RCC_CFGR_PLLMUL_12) + +/* SYSCLK = 24MHz */ +#define AO_PLLDIV		4 +#define AO_RCC_CFGR_PLLDIV	(STM_RCC_CFGR_PLLDIV_4) + +/* HCLK = 24MHz (CPU clock) */ +#define AO_AHB_PRESCALER	1 +#define AO_RCC_CFGR_HPRE_DIV	STM_RCC_CFGR_HPRE_DIV_1 + +/* Run APB1 at HCLK/1 */ +#define AO_APB1_PRESCALER	1 +#define AO_RCC_CFGR_PPRE1_DIV	STM_RCC_CFGR_PPRE1_DIV_1 + +/* Run APB2 at HCLK/1 */ +#define AO_APB2_PRESCALER	1 +#define AO_RCC_CFGR_PPRE2_DIV	STM_RCC_CFGR_PPRE2_DIV_1 + +/* Allow for non-maskable interrupts at priority 0 */ +#define AO_NONMASK_INTERRUPT	1 + +/* PS/2 keyboard connection */ +#define AO_PS2_CLOCK_PORT	(&stm_gpiod) +#define AO_PS2_CLOCK_BIT	9 +#define AO_PS2_DATA_PORT	(&stm_gpiod) +#define AO_PS2_DATA_BIT		8 + +#define HAS_SERIAL_1		1 +#define USE_SERIAL_1_STDIN	1 +#define SERIAL_1_PB6_PB7	1 +#define SERIAL_1_PA9_PA10	0 + +#define HAS_SERIAL_2		1 +#define USE_SERIAL_2_STDIN	1 +#define SERIAL_2_PA2_PA3	0 +#define SERIAL_2_PD5_PD6	1 + +#define HAS_SERIAL_3		0 +#define USE_SERIAL_3_STDIN	0 +#define SERIAL_3_PB10_PB11	0 +#define SERIAL_3_PC10_PC11	0 +#define SERIAL_3_PD8_PD9	0 + +#define HAS_EEPROM		0 +#define USE_INTERNAL_FLASH	0 +#define USE_EEPROM_CONFIG	0 +#define USE_STORAGE_CONFIG	0 +#define HAS_USB			1 +#define HAS_BEEP		0 +#define HAS_BATTERY_REPORT	0 +#define HAS_RADIO		0 +#define HAS_TELEMETRY		0 +#define HAS_APRS		0 +#define HAS_COMPANION		0 + +#define HAS_SPI_1		0 +#define SPI_1_PA5_PA6_PA7	0 +#define SPI_1_PB3_PB4_PB5	0 +#define SPI_1_PE13_PE14_PE15	0 +#define SPI_1_OSPEEDR		STM_OSPEEDR_10MHz + +#define HAS_SPI_2		1 +#define SPI_2_PB13_PB14_PB15	0 +#define SPI_2_PD1_PD3_PD4	1	/* LED displays, microSD */ +#define SPI_2_OSPEEDR		STM_OSPEEDR_40MHz + +#define SPI_2_PORT		(&stm_gpiod) +//#define SPI_2_SCK_PIN		1 +//#define SPI_2_MISO_PIN		3 +//#define SPI_2_MOSI_PIN		4 + +#define HAS_I2C_1		0 +#define I2C_1_PB8_PB9		0 + +#define HAS_I2C_2		0 +#define I2C_2_PB10_PB11		0 + +#define PACKET_HAS_SLAVE	0 +#define PACKET_HAS_MASTER	0 + +#define LOW_LEVEL_DEBUG		0 + +#define HAS_GPS			0 +#define HAS_FLIGHT		0 +#define HAS_ADC			0 +#define HAS_ADC_TEMP		0 +#define HAS_LOG			0 + +#define NUM_CMDS		16 + +/* SD card */ +#define AO_SDCARD_SPI_BUS	AO_SPI_2_PD1_PD3_PD4 +#define AO_SDCARD_SPI_CS_PORT	(&stm_gpiod) +#define AO_SDCARD_SPI_CS_PIN	2 +#define AO_SDCARD_SPI_PORT	(&stm_gpiod) +#define AO_SDCARD_SPI_SCK_PIN	1 +#define AO_SDCARD_SPI_MISO_PIN	3 +#define AO_SDCARD_SPI_MOSI_PIN	4 + +/* VGA */ +#define STM_DMA1_3_STOLEN	1 +/* Buttons */ + +#define AO_EVENT		1 + +#define AO_BUTTON_COUNT		4 +#define AO_BUTTON_MODE		AO_EXTI_MODE_PULL_DOWN +#define AO_BUTTON_INVERTED	0 + +/* INPUT */ +#define AO_BUTTON_0_PORT	(&stm_gpioc) +#define AO_BUTTON_0		8 + +/* MP */ +#define AO_BUTTON_1_PORT	(&stm_gpioc) +#define AO_BUTTON_1		9 + +/* RUN */ +#define AO_BUTTON_2_PORT	(&stm_gpioc) +#define AO_BUTTON_2		10 + +/* LOAD */ +#define AO_BUTTON_3_PORT	(&stm_gpioc) +#define AO_BUTTON_3		11 + +/* AS1107 */ +#define AO_AS1107_NUM_DIGITS	8 + +/* Set the hex digits up for decode, leave the extra leds alone */ + +#define AO_AS1107_DECODE	((1 << 7) |	\ +				 (1 << 6) |	\ +				 (1 << 4) |	\ +				 (1 << 3) |	\ +				 (1 << 1) |	\ +				 (1 << 0)) + +#define AO_AS1107_SPI_INDEX	AO_SPI_2_PD1_PD3_PD4 +#define AO_AS1107_SPI_SPEED	AO_SPI_SPEED_8MHz +#define AO_AS1107_CS_PORT	(&stm_gpiod) +#define AO_AS1107_CS_PIN	0 + +/* Hex keypad */ + +#define AO_MATRIX_ROWS	4 +#define AO_MATRIX_COLS	4 + +#define AO_MATRIX_KEYCODES {			\ +		{ 0x0, 0x1, 0x2, 0x3 },		\ +		{ 0x4, 0x5, 0x6, 0x7 },		\ +		{ 0x8, 0x9, 0xa, 0xb },		\ +		{ 0xc, 0xd, 0xe, 0xf }		\ +	} + +#include <ao_matrix.h> + +#define AO_TIMER_HOOK	ao_matrix_poll() + +#define AO_MATRIX_ROW_0_PORT	(&stm_gpioc) +#define AO_MATRIX_ROW_0_PIN	4 + +#define AO_MATRIX_ROW_1_PORT	(&stm_gpioc) +#define AO_MATRIX_ROW_1_PIN	1 + +#define AO_MATRIX_ROW_2_PORT	(&stm_gpioc) +#define AO_MATRIX_ROW_2_PIN	7 + +#define AO_MATRIX_ROW_3_PORT	(&stm_gpioc) +#define AO_MATRIX_ROW_3_PIN	0 + +#define AO_MATRIX_COL_0_PORT	(&stm_gpioc) +#define AO_MATRIX_COL_0_PIN	2 + +#define AO_MATRIX_COL_1_PORT	(&stm_gpioc) +#define AO_MATRIX_COL_1_PIN	3 + +#define AO_MATRIX_COL_2_PORT	(&stm_gpioc) +#define AO_MATRIX_COL_2_PIN	5 + +#define AO_MATRIX_COL_3_PORT	(&stm_gpioc) +#define AO_MATRIX_COL_3_PIN	6 + +/* 1802 connections */ +#define MRD_PORT		(&stm_gpiob) +#define MRD_BIT			15 + +#define MWR_PORT		(&stm_gpioa) +#define MWR_BIT			3 + +#define TPB_PORT		(&stm_gpioa) +#define TPB_BIT			7 + +#define TPA_PORT		(&stm_gpioa) +#define TPA_BIT			6 + +#define MA_PORT			(&stm_gpioe) +#define MA_SHIFT		0 +#define MA_MASK			0xff + +#define BUS_PORT		(&stm_gpioe) +#define BUS_SHIFT		8 +#define BUS_MASK		0xff + +#define SC_PORT			(&stm_gpiob) +#define SC_SHIFT		13 +#define SC_MASK			3 + +#define Q_PORT			(&stm_gpiob) +#define Q_BIT			12 + +#define N_PORT			(&stm_gpiod) +#define N_SHIFT			13 +#define N_MASK			7 + +#define EF_PORT			(&stm_gpiob) +#define EF_SHIFT		8 +#define EF_MASK			0xf + +#define DMA_IN_PORT		(&stm_gpioa) +#define DMA_IN_BIT		0 + +#define DMA_OUT_PORT		(&stm_gpioa) +#define DMA_OUT_BIT		9 + +#define INT_PORT		(&stm_gpioa) +#define INT_BIT			2 + +#define CLEAR_PORT		(&stm_gpioa) +#define CLEAR_BIT		10 + +#define WAIT_PORT		(&stm_gpioa) +#define WAIT_BIT		4 + +#define MUX_PORT		(&stm_gpiob) +#define MUX_BIT			1 + +#endif /* _AO_PINS_H_ */ diff --git a/src/cortexelf-v1/cortexelf.ld b/src/cortexelf-v1/cortexelf.ld new file mode 100644 index 00000000..6ad2a679 --- /dev/null +++ b/src/cortexelf-v1/cortexelf.ld @@ -0,0 +1,101 @@ +/* + * Copyright © 2017 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +MEMORY { +	rom (rx) :	ORIGIN = 0x08001000, LENGTH = 492K +	flash (r) :	ORIGIN = 0x0807c000, LENGTH = 16K +	ram (!w) :	ORIGIN = 0x20000000, LENGTH = 81408 +	stack (!w) :	ORIGIN = 0x20013e00, LENGTH = 512 +} + +INCLUDE registers.ld + +EXTERN (stm_interrupt_vector) + +SECTIONS { +	/* +	 * Rom contents +	 */ + +	.text ORIGIN(rom) : { +		__text_start__ = .; +		*(.interrupt)	/* Interrupt vectors */ + +		. = ORIGIN(rom) + 0x100; + + +		/* Ick. What I want is to specify the +		 * addresses of some global constants so +		 * that I can find them across versions +		 * of the application. I can't figure out +		 * how to make gnu ld do that, so instead +		 * we just load the two files that include +		 * these defines in the right order here and +		 * expect things to 'just work'. Don't change +		 * the contents of those files, ok? +		 */ +		ao_romconfig.o(.romconfig*) +		ao_product.o(.romconfig*) +		*(.text*)	/* Executable code */ +		*(.rodata*)	/* Constants */ + +	} > rom + +	.ARM.exidx : { +		*(.ARM.exidx* .gnu.linkonce.armexidx.*) +	} > rom +	__text_end__ = .; + +	/* Boot data which must live at the start of ram so that +	 * the application and bootloader share the same addresses. +	 * This must be all uninitialized data +	 */ +	.boot (NOLOAD) : { +		__boot_start__ = .; +		*(.boot) +		. = ALIGN(4); +		__boot_end__ = .; +	} >ram + +	/* Data -- relocated to RAM, but written to ROM +	 */ +	.data : { +		__data_start__ = .; +		*(.data)	/* initialized data */ +		. = ALIGN(4); +		__data_end__ = .; +	} >ram AT>rom + +	.bss : { +		__bss_start__ = .; +		*(.bss) +		*(COMMON) +		. = ALIGN(4); +		__bss_end__ = .; +	} >ram + +	PROVIDE(end = .); + +	PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack)); + +	__flash__ = ORIGIN(flash); +} + +ENTRY(start); + + diff --git a/src/cortexelf-v1/flash-loader/Makefile b/src/cortexelf-v1/flash-loader/Makefile new file mode 100644 index 00000000..19cf84e4 --- /dev/null +++ b/src/cortexelf-v1/flash-loader/Makefile @@ -0,0 +1,8 @@ +# +# AltOS flash loader build +# +# + +TOPDIR=../.. +HARDWARE=cortexelf-v1 +include $(TOPDIR)/stm/Makefile-flash.defs diff --git a/src/cortexelf-v1/flash-loader/ao_pins.h b/src/cortexelf-v1/flash-loader/ao_pins.h new file mode 100644 index 00000000..5d63dc2c --- /dev/null +++ b/src/cortexelf-v1/flash-loader/ao_pins.h @@ -0,0 +1,35 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +/* External crystal at 8MHz */ +#define AO_HSE		8000000 + +#include <ao_flash_stm_pins.h> + +/* MP switch, gpioc 9 */ + +#define AO_BOOT_PIN			1 +#define AO_BOOT_APPLICATION_GPIO	stm_gpioc +#define AO_BOOT_APPLICATION_PIN		9 +#define AO_BOOT_APPLICATION_VALUE	1 +#define AO_BOOT_APPLICATION_MODE	0 + +#endif /* _AO_PINS_H_ */ diff --git a/src/draw/5x7.bdf b/src/draw/5x7.bdf new file mode 100644 index 00000000..b511f289 --- /dev/null +++ b/src/draw/5x7.bdf @@ -0,0 +1,3190 @@ +STARTFONT 2.1 +COMMENT  Copyright 1991 Massachusetts Institute of Technology +COMMENT   +COMMENT  Permission to use, copy, modify, and distribute this software +COMMENT  and its documentation for any purpose and without fee is +COMMENT  hereby granted, provided that the above copyright notice +COMMENT  appear in all copies and that both that copyright notice and +COMMENT  this permission notice appear in supporting documentation, +COMMENT  and that the name of M.I.T. not be used in advertising or +COMMENT  publicity pertaining to distribution of the software without +COMMENT  specific, written prior permission.  M.I.T. makes no +COMMENT  representations about the suitability of this software for +COMMENT  any purpose.  It is provided "as is" without express or +COMMENT  implied warranty. +COMMENT   +COMMENT  M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +COMMENT  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +COMMENT  FITNESS, IN NO EVENT SHALL M.I.T.  BE LIABLE FOR ANY SPECIAL, +COMMENT  INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER +COMMENT  RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +COMMENT  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +COMMENT  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +COMMENT  OF THIS SOFTWARE. +COMMENT   +COMMENT  Author:  Stephen Gildea, MIT X Consortium, June 1991 +COMMENT   +FONT -Misc-Fixed-Medium-R-Normal--7-70-75-75-C-50-ISO8859-1 +SIZE 7 75 75 +FONTBOUNDINGBOX 5 7 0 -1 +STARTPROPERTIES 21 +FONTNAME_REGISTRY "" +FOUNDRY "Misc" +FAMILY_NAME "Fixed" +WEIGHT_NAME "Medium" +SLANT "R" +SETWIDTH_NAME "Normal" +ADD_STYLE_NAME "" +PIXEL_SIZE 7 +POINT_SIZE 70 +RESOLUTION_X 75 +RESOLUTION_Y 75 +SPACING "C" +AVERAGE_WIDTH 50 +CHARSET_REGISTRY "ISO8859" +CHARSET_ENCODING "1" +FONT_ASCENT 6 +FONT_DESCENT 1 +UNDERLINE_POSITION 0 +DESTINATION 1 +DEFAULT_CHAR 0 +COPYRIGHT "Copyright 1991 Massachusetts Institute of Technology" +ENDPROPERTIES +CHARS 224 +STARTCHAR C000 +ENCODING 0 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +f0 +f0 +f0 +f0 +f0 +f0 +00 +ENDCHAR +STARTCHAR C001 +ENCODING 1 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +20 +70 +f8 +70 +20 +00 +ENDCHAR +STARTCHAR C002 +ENCODING 2 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +50 +a0 +50 +a0 +50 +a0 +00 +ENDCHAR +STARTCHAR C003 +ENCODING 3 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +a0 +e0 +a0 +a0 +70 +20 +20 +ENDCHAR +STARTCHAR C004 +ENCODING 4 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +c0 +80 +c0 +b0 +20 +30 +20 +ENDCHAR +STARTCHAR C005 +ENCODING 5 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +c0 +80 +c0 +60 +50 +60 +50 +ENDCHAR +STARTCHAR C006 +ENCODING 6 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +80 +80 +c0 +30 +20 +30 +20 +ENDCHAR +STARTCHAR C007 +ENCODING 7 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +50 +20 +00 +00 +00 +00 +ENDCHAR +STARTCHAR C010 +ENCODING 8 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +70 +20 +00 +70 +00 +00 +ENDCHAR +STARTCHAR C011 +ENCODING 9 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +90 +d0 +b0 +90 +20 +20 +30 +ENDCHAR +STARTCHAR C012 +ENCODING 10 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +a0 +a0 +a0 +40 +70 +20 +20 +ENDCHAR +STARTCHAR C013 +ENCODING 11 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +20 +20 +e0 +00 +00 +00 +ENDCHAR +STARTCHAR C014 +ENCODING 12 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +e0 +20 +20 +20 +ENDCHAR +STARTCHAR C015 +ENCODING 13 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +38 +20 +20 +20 +ENDCHAR +STARTCHAR C016 +ENCODING 14 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +20 +20 +38 +00 +00 +00 +ENDCHAR +STARTCHAR C017 +ENCODING 15 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +20 +20 +f8 +20 +20 +20 +ENDCHAR +STARTCHAR C020 +ENCODING 16 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +f8 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR C021 +ENCODING 17 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 6 7 0 -1 +BITMAP +00 +00 +f8 +00 +00 +00 +00 +ENDCHAR +STARTCHAR C022 +ENCODING 18 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +f8 +00 +00 +00 +ENDCHAR +STARTCHAR C023 +ENCODING 19 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +00 +f8 +00 +00 +ENDCHAR +STARTCHAR C024 +ENCODING 20 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +00 +00 +f8 +00 +ENDCHAR +STARTCHAR C025 +ENCODING 21 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +20 +20 +38 +20 +20 +20 +ENDCHAR +STARTCHAR C026 +ENCODING 22 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +20 +20 +e0 +20 +20 +20 +ENDCHAR +STARTCHAR C027 +ENCODING 23 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 6 7 0 -1 +BITMAP +20 +20 +20 +f8 +00 +00 +00 +ENDCHAR +STARTCHAR C030 +ENCODING 24 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +f8 +20 +20 +20 +ENDCHAR +STARTCHAR C031 +ENCODING 25 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +20 +20 +20 +20 +20 +20 +ENDCHAR +STARTCHAR C032 +ENCODING 26 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +10 +20 +40 +20 +10 +70 +00 +ENDCHAR +STARTCHAR C033 +ENCODING 27 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +20 +10 +20 +40 +70 +00 +ENDCHAR +STARTCHAR C034 +ENCODING 28 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +70 +50 +50 +50 +00 +ENDCHAR +STARTCHAR C035 +ENCODING 29 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +10 +70 +20 +70 +40 +00 +ENDCHAR +STARTCHAR C036 +ENCODING 30 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +30 +40 +e0 +40 +b0 +00 +ENDCHAR +STARTCHAR C037 +ENCODING 31 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +20 +00 +00 +00 +ENDCHAR +STARTCHAR C040 +ENCODING 32 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR ! +ENCODING 33 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +20 +20 +20 +00 +20 +00 +ENDCHAR +STARTCHAR " +ENCODING 34 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +50 +50 +50 +00 +00 +00 +00 +ENDCHAR +STARTCHAR # +ENCODING 35 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +50 +f8 +50 +f8 +50 +00 +ENDCHAR +STARTCHAR $ +ENCODING 36 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +70 +a0 +70 +28 +70 +00 +ENDCHAR +STARTCHAR % +ENCODING 37 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +80 +90 +20 +40 +90 +10 +00 +ENDCHAR +STARTCHAR & +ENCODING 38 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +40 +a0 +40 +a0 +50 +00 +ENDCHAR +STARTCHAR ' +ENCODING 39 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +40 +80 +00 +00 +00 +00 +ENDCHAR +STARTCHAR ( +ENCODING 40 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +40 +40 +40 +40 +20 +00 +ENDCHAR +STARTCHAR ) +ENCODING 41 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +20 +20 +20 +20 +40 +00 +ENDCHAR +STARTCHAR * +ENCODING 42 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +a0 +40 +e0 +40 +a0 +00 +ENDCHAR +STARTCHAR + +ENCODING 43 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +20 +20 +f8 +20 +20 +00 +ENDCHAR +STARTCHAR , +ENCODING 44 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +00 +60 +40 +80 +ENDCHAR +STARTCHAR - +ENCODING 45 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +f0 +00 +00 +00 +ENDCHAR +STARTCHAR . +ENCODING 46 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +00 +60 +60 +00 +ENDCHAR +STARTCHAR / +ENCODING 47 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +10 +20 +40 +80 +00 +00 +ENDCHAR +STARTCHAR 0 +ENCODING 48 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +a0 +a0 +a0 +a0 +40 +00 +ENDCHAR +STARTCHAR 1 +ENCODING 49 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +c0 +40 +40 +40 +e0 +00 +ENDCHAR +STARTCHAR 2 +ENCODING 50 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +10 +20 +40 +f0 +00 +ENDCHAR +STARTCHAR 3 +ENCODING 51 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +f0 +10 +60 +10 +90 +60 +00 +ENDCHAR +STARTCHAR 4 +ENCODING 52 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +60 +a0 +f0 +20 +20 +00 +ENDCHAR +STARTCHAR 5 +ENCODING 53 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +f0 +80 +e0 +10 +90 +60 +00 +ENDCHAR +STARTCHAR 6 +ENCODING 54 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +80 +e0 +90 +90 +60 +00 +ENDCHAR +STARTCHAR 7 +ENCODING 55 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +f0 +10 +20 +20 +40 +40 +00 +ENDCHAR +STARTCHAR 8 +ENCODING 56 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +60 +90 +90 +60 +00 +ENDCHAR +STARTCHAR 9 +ENCODING 57 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +70 +10 +60 +00 +ENDCHAR +STARTCHAR : +ENCODING 58 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +60 +60 +00 +60 +60 +00 +ENDCHAR +STARTCHAR ; +ENCODING 59 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +60 +60 +00 +60 +40 +80 +ENDCHAR +STARTCHAR < +ENCODING 60 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +20 +40 +80 +40 +20 +00 +ENDCHAR +STARTCHAR = +ENCODING 61 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +f0 +00 +f0 +00 +00 +ENDCHAR +STARTCHAR > +ENCODING 62 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +80 +40 +20 +40 +80 +00 +ENDCHAR +STARTCHAR ? +ENCODING 63 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +a0 +20 +40 +00 +40 +00 +ENDCHAR +STARTCHAR @ +ENCODING 64 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +b0 +b0 +80 +60 +00 +ENDCHAR +STARTCHAR A +ENCODING 65 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +f0 +90 +90 +00 +ENDCHAR +STARTCHAR B +ENCODING 66 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +e0 +90 +e0 +90 +90 +e0 +00 +ENDCHAR +STARTCHAR C +ENCODING 67 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +80 +80 +90 +60 +00 +ENDCHAR +STARTCHAR D +ENCODING 68 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +e0 +90 +90 +90 +90 +e0 +00 +ENDCHAR +STARTCHAR E +ENCODING 69 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +f0 +80 +e0 +80 +80 +f0 +00 +ENDCHAR +STARTCHAR F +ENCODING 70 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +f0 +80 +e0 +80 +80 +80 +00 +ENDCHAR +STARTCHAR G +ENCODING 71 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +80 +b0 +90 +70 +00 +ENDCHAR +STARTCHAR H +ENCODING 72 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +90 +90 +f0 +90 +90 +90 +00 +ENDCHAR +STARTCHAR I +ENCODING 73 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +e0 +40 +40 +40 +40 +e0 +00 +ENDCHAR +STARTCHAR J +ENCODING 74 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +10 +10 +10 +10 +90 +60 +00 +ENDCHAR +STARTCHAR K +ENCODING 75 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +90 +a0 +c0 +c0 +a0 +90 +00 +ENDCHAR +STARTCHAR L +ENCODING 76 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +80 +80 +80 +80 +80 +f0 +00 +ENDCHAR +STARTCHAR M +ENCODING 77 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +90 +f0 +f0 +90 +90 +90 +00 +ENDCHAR +STARTCHAR N +ENCODING 78 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +90 +d0 +d0 +b0 +b0 +90 +00 +ENDCHAR +STARTCHAR O +ENCODING 79 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR P +ENCODING 80 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +e0 +90 +90 +e0 +80 +80 +00 +ENDCHAR +STARTCHAR Q +ENCODING 81 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +90 +d0 +60 +10 +ENDCHAR +STARTCHAR R +ENCODING 82 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +e0 +90 +90 +e0 +a0 +90 +00 +ENDCHAR +STARTCHAR S +ENCODING 83 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +40 +20 +90 +60 +00 +ENDCHAR +STARTCHAR T +ENCODING 84 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +e0 +40 +40 +40 +40 +40 +00 +ENDCHAR +STARTCHAR U +ENCODING 85 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +90 +90 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR V +ENCODING 86 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +90 +90 +90 +90 +60 +60 +00 +ENDCHAR +STARTCHAR W +ENCODING 87 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +90 +90 +90 +f0 +f0 +90 +00 +ENDCHAR +STARTCHAR X +ENCODING 88 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +90 +90 +60 +60 +90 +90 +00 +ENDCHAR +STARTCHAR Y +ENCODING 89 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +a0 +a0 +a0 +40 +40 +40 +00 +ENDCHAR +STARTCHAR Z +ENCODING 90 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +f0 +10 +20 +40 +80 +f0 +00 +ENDCHAR +STARTCHAR [ +ENCODING 91 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +e0 +80 +80 +80 +80 +e0 +00 +ENDCHAR +STARTCHAR \ +ENCODING 92 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +80 +40 +20 +10 +00 +00 +ENDCHAR +STARTCHAR ] +ENCODING 93 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +e0 +20 +20 +20 +20 +e0 +00 +ENDCHAR +STARTCHAR ^ +ENCODING 94 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +a0 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR _ +ENCODING 95 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +00 +00 +f0 +00 +ENDCHAR +STARTCHAR ` +ENCODING 96 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +c0 +40 +20 +00 +00 +00 +00 +ENDCHAR +STARTCHAR a +ENCODING 97 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +70 +90 +b0 +50 +00 +ENDCHAR +STARTCHAR b +ENCODING 98 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +80 +80 +e0 +90 +90 +e0 +00 +ENDCHAR +STARTCHAR c +ENCODING 99 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +60 +80 +80 +60 +00 +ENDCHAR +STARTCHAR d +ENCODING 100 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +10 +10 +70 +90 +90 +70 +00 +ENDCHAR +STARTCHAR e +ENCODING 101 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +60 +b0 +c0 +60 +00 +ENDCHAR +STARTCHAR f +ENCODING 102 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +50 +40 +e0 +40 +40 +00 +ENDCHAR +STARTCHAR g +ENCODING 103 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +70 +90 +60 +80 +70 +ENDCHAR +STARTCHAR h +ENCODING 104 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +80 +80 +e0 +90 +90 +90 +00 +ENDCHAR +STARTCHAR i +ENCODING 105 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +00 +c0 +40 +40 +e0 +00 +ENDCHAR +STARTCHAR j +ENCODING 106 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +00 +20 +20 +20 +a0 +40 +ENDCHAR +STARTCHAR k +ENCODING 107 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +80 +80 +a0 +c0 +a0 +90 +00 +ENDCHAR +STARTCHAR l +ENCODING 108 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +c0 +40 +40 +40 +40 +e0 +00 +ENDCHAR +STARTCHAR m +ENCODING 109 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +a0 +f0 +90 +90 +00 +ENDCHAR +STARTCHAR n +ENCODING 110 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +e0 +90 +90 +90 +00 +ENDCHAR +STARTCHAR o +ENCODING 111 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +60 +90 +90 +60 +00 +ENDCHAR +STARTCHAR p +ENCODING 112 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +e0 +90 +90 +e0 +80 +ENDCHAR +STARTCHAR q +ENCODING 113 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +70 +90 +90 +70 +10 +ENDCHAR +STARTCHAR r +ENCODING 114 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +e0 +90 +80 +80 +00 +ENDCHAR +STARTCHAR s +ENCODING 115 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 6 7 0 -1 +BITMAP +00 +00 +70 +c0 +30 +e0 +00 +ENDCHAR +STARTCHAR t +ENCODING 116 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +40 +e0 +40 +40 +30 +00 +ENDCHAR +STARTCHAR u +ENCODING 117 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +90 +90 +90 +70 +00 +ENDCHAR +STARTCHAR v +ENCODING 118 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +a0 +a0 +a0 +40 +00 +ENDCHAR +STARTCHAR w +ENCODING 119 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +90 +90 +f0 +f0 +00 +ENDCHAR +STARTCHAR x +ENCODING 120 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +90 +60 +60 +90 +00 +ENDCHAR +STARTCHAR y +ENCODING 121 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +90 +90 +50 +20 +40 +ENDCHAR +STARTCHAR z +ENCODING 122 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +f0 +20 +40 +f0 +00 +ENDCHAR +STARTCHAR { +ENCODING 123 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +40 +c0 +40 +40 +20 +00 +ENDCHAR +STARTCHAR | +ENCODING 124 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +40 +40 +40 +40 +40 +00 +ENDCHAR +STARTCHAR } +ENCODING 125 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 6 7 0 -1 +BITMAP +80 +40 +60 +40 +40 +80 +00 +ENDCHAR +STARTCHAR ~ +ENCODING 126 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +50 +a0 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR Blank +ENCODING 127 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR C160 +ENCODING 160 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR C161 +ENCODING 161 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +00 +20 +20 +20 +20 +00 +ENDCHAR +STARTCHAR C162 +ENCODING 162 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +20 +70 +a0 +a0 +70 +20 +ENDCHAR +STARTCHAR C163 +ENCODING 163 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +30 +40 +e0 +40 +b0 +00 +ENDCHAR +STARTCHAR C164 +ENCODING 164 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +88 +70 +50 +70 +88 +00 +ENDCHAR +STARTCHAR C165 +ENCODING 165 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +a0 +a0 +40 +e0 +40 +40 +00 +ENDCHAR +STARTCHAR C166 +ENCODING 166 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +20 +20 +00 +20 +20 +00 +ENDCHAR +STARTCHAR C167 +ENCODING 167 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +30 +40 +60 +50 +30 +10 +60 +ENDCHAR +STARTCHAR C168 +ENCODING 168 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +50 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR C169 +ENCODING 169 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +70 +88 +a8 +c8 +a8 +88 +70 +ENDCHAR +STARTCHAR C170 +ENCODING 170 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +a0 +60 +00 +00 +00 +00 +ENDCHAR +STARTCHAR C171 +ENCODING 171 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +48 +90 +48 +00 +00 +ENDCHAR +STARTCHAR C172 +ENCODING 172 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +f0 +10 +00 +00 +00 +ENDCHAR +STARTCHAR C173 +ENCODING 173 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +f0 +00 +00 +00 +ENDCHAR +STARTCHAR C174 +ENCODING 174 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +70 +88 +e8 +c8 +c8 +88 +70 +ENDCHAR +STARTCHAR C175 +ENCODING 175 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +f0 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR C176 +ENCODING 176 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +50 +20 +00 +00 +00 +00 +ENDCHAR +STARTCHAR C177 +ENCODING 177 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +20 +f8 +20 +20 +f8 +00 +ENDCHAR +STARTCHAR C178 +ENCODING 178 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +20 +40 +60 +00 +00 +00 +ENDCHAR +STARTCHAR C179 +ENCODING 179 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +60 +20 +60 +00 +00 +00 +ENDCHAR +STARTCHAR C180 +ENCODING 180 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +40 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR C181 +ENCODING 181 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +90 +90 +90 +e0 +80 +ENDCHAR +STARTCHAR C182 +ENCODING 182 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +70 +d0 +d0 +50 +50 +50 +00 +ENDCHAR +STARTCHAR C183 +ENCODING 183 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +60 +60 +00 +00 +00 +00 +ENDCHAR +STARTCHAR C184 +ENCODING 184 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +00 +00 +20 +40 +ENDCHAR +STARTCHAR C185 +ENCODING 185 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +60 +20 +70 +00 +00 +00 +ENDCHAR +STARTCHAR C186 +ENCODING 186 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +a0 +40 +00 +00 +00 +00 +ENDCHAR +STARTCHAR C187 +ENCODING 187 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +90 +48 +90 +00 +00 +ENDCHAR +STARTCHAR C188 +ENCODING 188 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +80 +80 +80 +90 +30 +70 +10 +ENDCHAR +STARTCHAR C189 +ENCODING 189 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +80 +80 +80 +b0 +10 +20 +30 +ENDCHAR +STARTCHAR C190 +ENCODING 190 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +c0 +c0 +40 +d0 +30 +70 +10 +ENDCHAR +STARTCHAR C191 +ENCODING 191 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +00 +40 +80 +a0 +40 +00 +ENDCHAR +STARTCHAR Agrave +ENCODING 192 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +f0 +90 +90 +00 +ENDCHAR +STARTCHAR C193 +ENCODING 193 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +f0 +90 +90 +00 +ENDCHAR +STARTCHAR C194 +ENCODING 194 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +f0 +90 +90 +00 +ENDCHAR +STARTCHAR C195 +ENCODING 195 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +f0 +90 +90 +00 +ENDCHAR +STARTCHAR C196 +ENCODING 196 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +f0 +90 +90 +00 +ENDCHAR +STARTCHAR C197 +ENCODING 197 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +f0 +90 +90 +00 +ENDCHAR +STARTCHAR C198 +ENCODING 198 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +70 +a0 +b0 +e0 +a0 +b0 +00 +ENDCHAR +STARTCHAR C199 +ENCODING 199 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +80 +80 +90 +60 +40 +ENDCHAR +STARTCHAR Egrave +ENCODING 200 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +f0 +80 +e0 +80 +80 +f0 +00 +ENDCHAR +STARTCHAR C201 +ENCODING 201 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +f0 +80 +e0 +80 +80 +f0 +00 +ENDCHAR +STARTCHAR C202 +ENCODING 202 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +f0 +80 +e0 +80 +80 +f0 +00 +ENDCHAR +STARTCHAR C203 +ENCODING 203 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +f0 +80 +e0 +80 +80 +f0 +00 +ENDCHAR +STARTCHAR C204 +ENCODING 204 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +e0 +40 +40 +40 +40 +e0 +00 +ENDCHAR +STARTCHAR C205 +ENCODING 205 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +e0 +40 +40 +40 +40 +e0 +00 +ENDCHAR +STARTCHAR C206 +ENCODING 206 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +e0 +40 +40 +40 +40 +e0 +00 +ENDCHAR +STARTCHAR C207 +ENCODING 207 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +e0 +40 +40 +40 +40 +e0 +00 +ENDCHAR +STARTCHAR C208 +ENCODING 208 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +e0 +50 +d0 +50 +50 +e0 +00 +ENDCHAR +STARTCHAR C209 +ENCODING 209 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +b0 +90 +d0 +b0 +b0 +90 +00 +ENDCHAR +STARTCHAR Ograve +ENCODING 210 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C211 +ENCODING 211 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C212 +ENCODING 212 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C213 +ENCODING 213 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C214 +ENCODING 214 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C215 +ENCODING 215 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +90 +60 +60 +90 +00 +ENDCHAR +STARTCHAR C216 +ENCODING 216 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +70 +b0 +b0 +d0 +d0 +e0 +00 +ENDCHAR +STARTCHAR Ugrave +ENCODING 217 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +90 +90 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C218 +ENCODING 218 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +90 +90 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C219 +ENCODING 219 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +90 +90 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C220 +ENCODING 220 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +90 +90 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C221 +ENCODING 221 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +a0 +a0 +a0 +40 +40 +40 +00 +ENDCHAR +STARTCHAR C222 +ENCODING 222 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +80 +e0 +90 +e0 +80 +80 +00 +ENDCHAR +STARTCHAR C223 +ENCODING 223 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +e0 +90 +d0 +a0 +80 +ENDCHAR +STARTCHAR a-grave +ENCODING 224 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +20 +70 +90 +b0 +50 +00 +ENDCHAR +STARTCHAR C225 +ENCODING 225 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +40 +70 +90 +b0 +50 +00 +ENDCHAR +STARTCHAR C226 +ENCODING 226 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +50 +70 +90 +b0 +50 +00 +ENDCHAR +STARTCHAR C227 +ENCODING 227 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +50 +a0 +70 +90 +b0 +50 +00 +ENDCHAR +STARTCHAR C228 +ENCODING 228 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +50 +00 +70 +90 +b0 +50 +00 +ENDCHAR +STARTCHAR C229 +ENCODING 229 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +60 +70 +90 +b0 +50 +00 +ENDCHAR +STARTCHAR C230 +ENCODING 230 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +70 +b0 +a0 +70 +00 +ENDCHAR +STARTCHAR C231 +ENCODING 231 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +60 +80 +80 +60 +40 +ENDCHAR +STARTCHAR e-grave +ENCODING 232 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +20 +60 +b0 +c0 +60 +00 +ENDCHAR +STARTCHAR C233 +ENCODING 233 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +40 +60 +b0 +c0 +60 +00 +ENDCHAR +STARTCHAR C234 +ENCODING 234 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +a0 +60 +b0 +c0 +60 +00 +ENDCHAR +STARTCHAR C235 +ENCODING 235 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +a0 +00 +60 +b0 +c0 +60 +00 +ENDCHAR +STARTCHAR C236 +ENCODING 236 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +80 +40 +c0 +40 +40 +e0 +00 +ENDCHAR +STARTCHAR C237 +ENCODING 237 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +80 +c0 +40 +40 +e0 +00 +ENDCHAR +STARTCHAR C238 +ENCODING 238 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +a0 +c0 +40 +40 +e0 +00 +ENDCHAR +STARTCHAR C239 +ENCODING 239 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +a0 +00 +c0 +40 +40 +e0 +00 +ENDCHAR +STARTCHAR C240 +ENCODING 240 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +30 +60 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C241 +ENCODING 241 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +50 +a0 +e0 +90 +90 +90 +00 +ENDCHAR +STARTCHAR C242 +ENCODING 242 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +20 +60 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C243 +ENCODING 243 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +40 +60 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C244 +ENCODING 244 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +00 +60 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C245 +ENCODING 245 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +50 +a0 +60 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C246 +ENCODING 246 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +a0 +00 +60 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C247 +ENCODING 247 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +60 +00 +f0 +00 +60 +00 +ENDCHAR +STARTCHAR C248 +ENCODING 248 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +70 +b0 +d0 +e0 +00 +ENDCHAR +STARTCHAR C249 +ENCODING 249 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +20 +90 +90 +90 +70 +00 +ENDCHAR +STARTCHAR C250 +ENCODING 250 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +40 +90 +90 +90 +70 +00 +ENDCHAR +STARTCHAR C251 +ENCODING 251 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +00 +90 +90 +90 +70 +00 +ENDCHAR +STARTCHAR C252 +ENCODING 252 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +50 +00 +90 +90 +90 +70 +00 +ENDCHAR +STARTCHAR C253 +ENCODING 253 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +40 +90 +90 +50 +20 +40 +ENDCHAR +STARTCHAR C254 +ENCODING 254 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +80 +e0 +90 +90 +e0 +80 +ENDCHAR +STARTCHAR C255 +ENCODING 255 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +50 +00 +90 +90 +50 +20 +40 +ENDCHAR +ENDFONT diff --git a/src/draw/Makefile b/src/draw/Makefile new file mode 100644 index 00000000..0a542a1f --- /dev/null +++ b/src/draw/Makefile @@ -0,0 +1,4 @@ +BDF=5x7.bdf + +ao_font.h: font-convert $(BDF) +	nickle font-convert $(BDF) > $@ diff --git a/src/draw/ao_blt.c b/src/draw/ao_blt.c new file mode 100644 index 00000000..e3f45221 --- /dev/null +++ b/src/draw/ao_blt.c @@ -0,0 +1,294 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include "ao.h" +#include "ao_draw.h" +#include "ao_draw_int.h" + +#define O 0 +#define I AO_ALLONES + +struct ao_merge_rop { +	uint32_t	ca1, cx1, ca2, cx2; +}; + +const struct ao_merge_rop ao_merge_rop[16] = { +    {O, O, O, O},               /* clear         0x0         0 */ +    {I, O, O, O},               /* and           0x1         src AND dst */ +    {I, O, I, O},               /* andReverse    0x2         src AND NOT dst */ +    {O, O, I, O},               /* copy          0x3         src */ +    {I, I, O, O},               /* andInverted   0x4         NOT src AND dst */ +    {O, I, O, O},               /* noop          0x5         dst */ +    {O, I, I, O},               /* xor           0x6         src XOR dst */ +    {I, I, I, O},               /* or            0x7         src OR dst */ +    {I, I, I, I},               /* nor           0x8         NOT src AND NOT dst */ +    {O, I, I, I},               /* equiv         0x9         NOT src XOR dst */ +    {O, I, O, I},               /* invert        0xa         NOT dst */ +    {I, I, O, I},               /* orReverse     0xb         src OR NOT dst */ +    {O, O, I, I},               /* copyInverted  0xc         NOT src */ +    {I, O, I, I},               /* orInverted    0xd         NOT src OR dst */ +    {I, O, O, I},               /* nand          0xe         NOT src OR NOT dst */ +    {O, O, O, I},               /* set           0xf         1 */ +}; + +#define ao_do_merge_rop(src, dst) \ +    (((dst) & (((src) & _ca1) ^ _cx1)) ^ (((src) & _ca2) ^ _cx2)) + +#define ao_do_dst_invarient_merge_rop(src)	(((src) & _ca2) ^ _cx2) + +#define ao_do_mask_merge_rop(src, dst, mask) \ +    (((dst) & ((((src) & _ca1) ^ _cx1) | ~(mask))) ^ ((((src) & _ca2) ^ _cx2) & (mask))) + +#define ao_dst_invarient_merge_rop()   (_ca1 == 0 && _cx1 == 0) + +void +ao_blt(uint32_t		*src_line, +       int16_t		src_stride, +       int16_t		src_x, +       uint32_t		*dst_line, +       int16_t		dst_stride, +       int16_t		dst_x, +       int16_t		width, +       int16_t		height, +       uint8_t		rop, +       uint8_t		reverse, +       uint8_t		upsidedown) +{ +	uint32_t	*src, *dst; +	uint32_t	_ca1, _cx1, _ca2, _cx2; +	uint8_t		dst_invarient; +	uint32_t	startmask, endmask; +	int16_t		nmiddle, n; +	uint32_t	bits1, bits; +	int16_t		left_shift, right_shift; + +	_ca1 = ao_merge_rop[rop].ca1; +	_cx1 = ao_merge_rop[rop].cx1; +	_ca2 = ao_merge_rop[rop].ca2; +	_cx2 = ao_merge_rop[rop].cx2; +	dst_invarient = ao_dst_invarient_merge_rop(); + +	if (upsidedown) { +		src_line += (height - 1) * src_stride; +		dst_line += (height - 1) * dst_stride; +		src_stride = -src_stride; +		dst_stride = -dst_stride; +	} + +	ao_mask_bits(dst_x, width, startmask, nmiddle, endmask); +	if (reverse) { +		src_line += ((src_x + width - 1) >> AO_SHIFT) + 1; +		dst_line += ((dst_x + width - 1) >> AO_SHIFT) + 1; +		src_x = (src_x + width - 1) & AO_MASK; +		dst_x = (dst_x + width - 1) & AO_MASK; +	} else { +		src_line += src_x >> AO_SHIFT; +		dst_line += dst_x >> AO_SHIFT; +		src_x &= AO_MASK; +		dst_x &= AO_MASK; +	} +	if (src_x == dst_x) { +		while (height--) { +			src = src_line; +			src_line += src_stride; +			dst = dst_line; +			dst_line += dst_stride; +			if (reverse) { +				if (endmask) { +					bits = *--src; +					--dst; +					*dst = ao_do_mask_merge_rop(bits, *dst, endmask); +				} +				n = nmiddle; +				if (dst_invarient) { +					while (n--) +						*--dst = ao_do_dst_invarient_merge_rop(*--src); +				} +				else { +					while (n--) { +						bits = *--src; +						--dst; +						*dst = ao_do_merge_rop(bits, *dst); +					} +				} +				if (startmask) { +					bits = *--src; +					--dst; +					*dst = ao_do_mask_merge_rop(bits, *dst, startmask); +				} +			} +			else { +				if (startmask) { +					bits = *src++; +					*dst = ao_do_mask_merge_rop(bits, *dst, startmask); +					dst++; +				} +				n = nmiddle; +				if (dst_invarient) { +					while (n--) +						*dst++ = ao_do_dst_invarient_merge_rop(*src++); +				} +				else { +					while (n--) { +						bits = *src++; +						*dst = ao_do_merge_rop(bits, *dst); +						dst++; +					} +				} +				if (endmask) { +					bits = *src; +					*dst = ao_do_mask_merge_rop(bits, *dst, endmask); +				} +			} +		} +	} else { +		if (src_x > dst_x) { +			left_shift = src_x - dst_x; +			right_shift = AO_UNIT - left_shift; +		} else { +			right_shift = dst_x - src_x; +			left_shift = AO_UNIT - right_shift; +		} +		while (height--) { +			src = src_line; +			src_line += src_stride; +			dst = dst_line; +			dst_line += dst_stride; + +			bits1 = 0; +			if (reverse) { +				if (src_x < dst_x) +					bits1 = *--src; +				if (endmask) { +					bits = ao_right(bits1, right_shift); +					if (ao_right(endmask, left_shift)) { +						bits1 = *--src; +						bits |= ao_left(bits1, left_shift); +					} +					--dst; +					*dst = ao_do_mask_merge_rop(bits, *dst, endmask); +				} +				n = nmiddle; +				if (dst_invarient) { +					while (n--) { +						bits = ao_right(bits1, right_shift); +						bits1 = *--src; +						bits |= ao_left(bits1, left_shift); +						--dst; +						*dst = ao_do_dst_invarient_merge_rop(bits); +					} +				} else { +					while (n--) { +						bits = ao_right(bits1, right_shift); +						bits1 = *--src; +						bits |= ao_left(bits1, left_shift); +						--dst; +						*dst = ao_do_merge_rop(bits, *dst); +					} +				} +				if (startmask) { +					bits = ao_right(bits1, right_shift); +					if (ao_right(startmask, left_shift)) { +						bits1 = *--src; +						bits |= ao_left(bits1, left_shift); +					} +					--dst; +					*dst = ao_do_mask_merge_rop(bits, *dst, startmask); +				} +			} +			else { +				if (src_x > dst_x) +					bits1 = *src++; +				if (startmask) { +					bits = ao_left(bits1, left_shift); +					if (ao_left(startmask, right_shift)) { +						bits1 = *src++; +						bits |= ao_right(bits1, right_shift); +					} +					*dst = ao_do_mask_merge_rop(bits, *dst, startmask); +					dst++; +				} +				n = nmiddle; +				if (dst_invarient) { +					while (n--) { +						bits = ao_left(bits1, left_shift); +						bits1 = *src++; +						bits |= ao_right(bits1, right_shift); +						*dst = ao_do_dst_invarient_merge_rop(bits); +						dst++; +					} +				} +				else { +					while (n--) { +						bits = ao_left(bits1, left_shift); +						bits1 = *src++; +						bits |= ao_right(bits1, right_shift); +						*dst = ao_do_merge_rop(bits, *dst); +						dst++; +					} +				} +				if (endmask) { +					bits = ao_left(bits1, left_shift); +					if (ao_left(endmask, right_shift)) { +						bits1 = *src; +						bits |= ao_right(bits1, right_shift); +					} +					*dst = ao_do_mask_merge_rop(bits, *dst, endmask); +				} +			} +		} +	} +} + +void +ao_solid(uint32_t	and, +	 uint32_t	xor, +	 uint32_t	*dst, +	 int16_t	dst_stride, +	 int16_t	dst_x, +	 int16_t	width, +	 int16_t	height) +{ +	uint32_t	startmask, endmask; +	int16_t		nmiddle; +	int16_t		n; + +	dst += dst_x >> AO_SHIFT; +	dst_x &= AO_MASK; + +	ao_mask_bits(dst_x, width, startmask, nmiddle, endmask); + +	if (startmask) +		dst_stride--; + +	dst_stride -= nmiddle; +	while (height--) { +		if (startmask) { +			*dst = ao_do_mask_rrop(*dst, and, xor, startmask); +			dst++; +		} +		n = nmiddle; +		if (!and) +			while (n--) +				*dst++ = xor; +		else +			while (n--) { +				*dst = ao_do_rrop(*dst, and, xor); +				dst++; +			} +		if (endmask) +			*dst = ao_do_mask_rrop(*dst, and, xor, endmask); +		dst += dst_stride; +	} +} diff --git a/src/draw/ao_copy.c b/src/draw/ao_copy.c new file mode 100644 index 00000000..47067bb8 --- /dev/null +++ b/src/draw/ao_copy.c @@ -0,0 +1,75 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include "ao.h" +#include "ao_draw.h" +#include "ao_draw_int.h" + +#define bound(val,max,other) do {		\ +		if (val < 0) {			\ +			other -= val;		\ +			val = 0;		\ +		}				\ +		if (val > max) {		\ +			other -= (val - max);	\ +			val = max;		\ +		}				\ +	} while (0) + +#define bound2(a, max_a, b, max_b) do {		\ +		bound(a, max_a, b);		\ +		bound(b, max_b, a);		\ +	} while (0) + +void +ao_copy(const struct ao_bitmap	*dst, +	int16_t			dst_x, +	int16_t			dst_y, +	int16_t			width, +	int16_t			height, +	const struct ao_bitmap	*src, +	int16_t			src_x, +	int16_t			src_y, +	uint8_t			rop) +{ +	int16_t		dst_x2 = dst_x + width, dst_y2 = dst_y + height; +	int16_t		src_x2 = src_x + width, src_y2 = src_y + height; +	uint8_t		reverse = 0; +	uint8_t		upsidedown = 0; + +	bound2(dst_x, dst->width, src_x, src->width); +	bound2(dst_x2, dst->width, src_x2, src->width); +	bound2(dst_y, dst->height, src_y, src->height); +	bound2(dst_y2, dst->height, src_y2, src->height); + +	if (dst == src) { +		reverse = (dst_x > src_x); +		upsidedown = (dst_y > src_y); +	} + +	if (dst_x < dst_x2 && dst_y < dst_y2) { +		ao_blt(src->base + src_y * src->stride, +		       src->stride, +		       src_x, +		       dst->base + dst_y * dst->stride, +		       dst->stride, +		       dst_x, +		       dst_x2 - dst_x, +		       dst_y2 - dst_y, +		       rop, +		       reverse, +		       upsidedown); +	} +} + diff --git a/src/draw/ao_draw.h b/src/draw/ao_draw.h new file mode 100644 index 00000000..92150fc1 --- /dev/null +++ b/src/draw/ao_draw.h @@ -0,0 +1,119 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef _AO_DRAW_H_ +#define _AO_DRAW_H_ + +struct ao_bitmap { +	uint32_t	*base; +	int16_t		stride;	/* in units */ +	int16_t		width;	/* in pixels */ +	int16_t		height;	/* in pixels */ +}; + +struct ao_pattern { +	uint8_t		pattern[8]; +}; + +void +ao_copy(const struct ao_bitmap	*dst, +	int16_t			dst_x, +	int16_t			dst_y, +	int16_t			width, +	int16_t			height, +	const struct ao_bitmap	*src, +	int16_t			src_x, +	int16_t			src_y, +	uint8_t			rop); + +void +ao_rect(const struct ao_bitmap	*dst, +	int16_t			x, +	int16_t			y, +	int16_t			width, +	int16_t			height, +	uint32_t		fill, +	uint8_t			rop); + +void +ao_pattern(const struct ao_bitmap	*dst, +	   int16_t			x, +	   int16_t			y, +	   int16_t			width, +	   int16_t			height, +	   const struct ao_pattern	*pattern, +	   int16_t			pat_x, +	   int16_t			pat_y, +	   uint8_t			rop); + +void +ao_line(const struct ao_bitmap	*dst, +	int16_t			x1, +	int16_t			y1, +	int16_t			x2, +	int16_t			y2, +	uint32_t		fill, +	uint8_t			rop); + +void +ao_text(const struct ao_bitmap	*dst, +	int16_t			x, +	int16_t			y, +	char			*string, +	uint32_t		fill, +	uint8_t			rop); + +struct ao_font { +	int	width; +	int	height; +	int	ascent; +	int	descent; +}; + +extern const struct ao_font ao_font; + +#define AO_SHIFT	5 +#define AO_UNIT		(1 << AO_SHIFT) +#define AO_MASK		(AO_UNIT - 1) +#define AO_ALLONES	((uint32_t) -1) + +/* + *	    dst + *	   0   1 + * + *	0  a   b + *  src + *	1  c   d + * + *	ROP = abcd + */ + +#define AO_CLEAR         0x0	/* 0 */ +#define AO_AND           0x1	/* src AND dst */ +#define AO_AND_REVERSE   0x2	/* src AND NOT dst */ +#define AO_COPY          0x3	/* src */ +#define AO_AND_INVERTED  0x4	/* NOT src AND dst */ +#define AO_NOOP          0x5	/* dst */ +#define AO_XOR           0x6	/* src XOR dst */ +#define AO_OR            0x7	/* src OR dst */ +#define AO_NOR           0x8	/* NOT src AND NOT dst */ +#define AO_EQUIV         0x9	/* NOT src XOR dst */ +#define AO_INVERT        0xa	/* NOT dst */ +#define AO_OR_REVERSE    0xb	/* src OR NOT dst */ +#define AO_COPY_INVERTED 0xc	/* NOT src */ +#define AO_OR_INVERTED   0xd	/* NOT src OR dst */ +#define AO_NAND          0xe	/* NOT src OR NOT dst */ +#define AO_SET           0xf	/* 1 */ + +#endif /* _AO_DRAW_H_ */ diff --git a/src/draw/ao_draw_int.h b/src/draw/ao_draw_int.h new file mode 100644 index 00000000..433aa409 --- /dev/null +++ b/src/draw/ao_draw_int.h @@ -0,0 +1,136 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef _AO_DRAW_INT_H_ +#define _AO_DRAW_INT_H_ + +static inline uint32_t +ao_expand(uint32_t bits) +{ +	return ~((bits & 1)-1); +} + +static inline uint32_t +ao_xor(uint8_t rop, uint32_t fg) +{ +	fg = ao_expand(fg); + +	return (fg & ao_expand(rop >> 1)) | +		(~fg & ao_expand(rop >> 3)); +} + +static inline uint32_t +ao_and(uint8_t rop, uint32_t fg) +{ +	fg = ao_expand(fg); + +	return (fg & ao_expand(rop ^ (rop >> 1))) | +		(~fg & ao_expand((rop>>2) ^ (rop>>3))); +} + +static inline uint32_t +ao_left(uint32_t bits, int16_t shift) { +	return bits >> shift; +} + +static inline uint32_t +ao_right(uint32_t bits, int16_t shift) { +	return bits << shift; +} + +static inline uint32_t +ao_right_mask(int16_t x) { +	if ((AO_UNIT - x) & AO_MASK) +		return ao_left(AO_ALLONES,(AO_UNIT - x) & AO_MASK); +	else +		return 0; +} + +static inline uint32_t +ao_left_mask(int16_t x) { +	if (x & AO_MASK) +		return ao_right(AO_ALLONES, x & AO_MASK); +	else +		return 0; +} + +static inline uint32_t +ao_bits_mask(int16_t x, int16_t w) { +	return ao_right(AO_ALLONES, x & AO_MASK) & +		ao_left(AO_ALLONES,(AO_UNIT - (x + w)) & AO_MASK); +} + +#define ao_mask_bits(x,w,l,n,r) { \ +    n = (w); \ +    r = ao_right_mask((x)+n); \ +    l = ao_left_mask(x); \ +    if (l) { \ +	n -= AO_UNIT - ((x) & AO_MASK); \ +	if (n < 0) { \ +	    n = 0; \ +	    l &= r; \ +	    r = 0; \ +	} \ +    } \ +    n >>= AO_SHIFT; \ +} + +#define ao_clip(val,min,max) do {		\ +		if (val < min) {		\ +			val = min;		\ +		} else if (val > max) {		\ +			val = max;		\ +		}				\ +	} while (0) + +static inline uint32_t +ao_do_mask_rrop(uint32_t dst, uint32_t and, uint32_t xor, uint32_t mask) { +	return (dst & (and | ~mask)) ^ (xor & mask); +} + +static inline uint32_t +ao_do_rrop(uint32_t dst, uint32_t and, uint32_t xor) { +	return (dst & and) ^ xor; +} + +void +ao_blt(uint32_t		*src_line, +       int16_t		src_stride, +       int16_t		src_x, +       uint32_t		*dst_line, +       int16_t		dst_stride, +       int16_t		dst_x, +       int16_t		width, +       int16_t		height, +       uint8_t		rop, +       uint8_t		reverse, +       uint8_t		upsidedown); + +void +ao_solid(uint32_t	and, +	 uint32_t	xor, +	 uint32_t	*dst, +	 int16_t	dst_stride, +	 int16_t	dst_x, +	 int16_t	width, +	 int16_t	height); + +int16_t +ao_glyph(const struct ao_bitmap	*dst, +	 int16_t		x, +	 int16_t		y, +	 uint8_t		c, +	 uint8_t		rop); + +#endif /* _AO_DRAW_INT_H_ */ diff --git a/src/draw/ao_font.h b/src/draw/ao_font.h new file mode 100644 index 00000000..5e31dd11 --- /dev/null +++ b/src/draw/ao_font.h @@ -0,0 +1,139 @@ +static const uint8_t glyph_bytes[1568] = { +	0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x04, 0x0e, 0x1f, 0x0e, 0x04, 0x00, 0x0a, 0x05,  +	0x0a, 0x05, 0x0a, 0x05, 0x00, 0x05, 0x07, 0x05, 0x05, 0x0e, 0x04, 0x04, 0x03, 0x01, 0x03, 0x0d,  +	0x04, 0x0c, 0x04, 0x03, 0x01, 0x03, 0x06, 0x0a, 0x06, 0x0a, 0x01, 0x01, 0x03, 0x0c, 0x04, 0x0c,  +	0x04, 0x04, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0e, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x09,  +	0x0b, 0x0d, 0x09, 0x04, 0x04, 0x0c, 0x05, 0x05, 0x05, 0x02, 0x0e, 0x04, 0x04, 0x04, 0x04, 0x04,  +	0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x1c, 0x04,  +	0x04, 0x04, 0x04, 0x04, 0x04, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x1f, 0x04, 0x04, 0x04,  +	0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  +	0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  +	0x00, 0x1f, 0x00, 0x04, 0x04, 0x04, 0x1c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x07, 0x04, 0x04,  +	0x04, 0x04, 0x04, 0x04, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x04, 0x04, 0x04, 0x04,  +	0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x04, 0x02, 0x04, 0x08, 0x0e, 0x00, 0x02, 0x04, 0x08,  +	0x04, 0x02, 0x0e, 0x00, 0x00, 0x00, 0x0e, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x08, 0x0e, 0x04, 0x0e,  +	0x02, 0x00, 0x00, 0x0c, 0x02, 0x07, 0x02, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,  +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x00, 0x04, 0x00, 0x0a, 0x0a,  +	0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x1f, 0x0a, 0x1f, 0x0a, 0x00, 0x00, 0x0e, 0x05, 0x0e,  +	0x14, 0x0e, 0x00, 0x01, 0x09, 0x04, 0x02, 0x09, 0x08, 0x00, 0x00, 0x02, 0x05, 0x02, 0x05, 0x0a,  +	0x00, 0x06, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x02, 0x02, 0x02, 0x04, 0x00, 0x02,  +	0x04, 0x04, 0x04, 0x04, 0x02, 0x00, 0x00, 0x05, 0x02, 0x07, 0x02, 0x05, 0x00, 0x00, 0x04, 0x04,  +	0x1f, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x02, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00,  +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x08, 0x04, 0x02, 0x01, 0x00, 0x00,  +	0x02, 0x05, 0x05, 0x05, 0x05, 0x02, 0x00, 0x02, 0x03, 0x02, 0x02, 0x02, 0x07, 0x00, 0x06, 0x09,  +	0x08, 0x04, 0x02, 0x0f, 0x00, 0x0f, 0x08, 0x06, 0x08, 0x09, 0x06, 0x00, 0x04, 0x06, 0x05, 0x0f,  +	0x04, 0x04, 0x00, 0x0f, 0x01, 0x07, 0x08, 0x09, 0x06, 0x00, 0x06, 0x01, 0x07, 0x09, 0x09, 0x06,  +	0x00, 0x0f, 0x08, 0x04, 0x04, 0x02, 0x02, 0x00, 0x06, 0x09, 0x06, 0x09, 0x09, 0x06, 0x00, 0x06,  +	0x09, 0x09, 0x0e, 0x08, 0x06, 0x00, 0x00, 0x06, 0x06, 0x00, 0x06, 0x06, 0x00, 0x00, 0x06, 0x06,  +	0x00, 0x06, 0x02, 0x01, 0x00, 0x04, 0x02, 0x01, 0x02, 0x04, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0f,  +	0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x02, 0x01, 0x00, 0x02, 0x05, 0x04, 0x02, 0x00, 0x02, 0x00,  +	0x06, 0x09, 0x0d, 0x0d, 0x01, 0x06, 0x00, 0x06, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x00, 0x07, 0x09,  +	0x07, 0x09, 0x09, 0x07, 0x00, 0x06, 0x09, 0x01, 0x01, 0x09, 0x06, 0x00, 0x07, 0x09, 0x09, 0x09,  +	0x09, 0x07, 0x00, 0x0f, 0x01, 0x07, 0x01, 0x01, 0x0f, 0x00, 0x0f, 0x01, 0x07, 0x01, 0x01, 0x01,  +	0x00, 0x06, 0x09, 0x01, 0x0d, 0x09, 0x0e, 0x00, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x09, 0x00, 0x07,  +	0x02, 0x02, 0x02, 0x02, 0x07, 0x00, 0x08, 0x08, 0x08, 0x08, 0x09, 0x06, 0x00, 0x09, 0x05, 0x03,  +	0x03, 0x05, 0x09, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x0f, 0x00, 0x09, 0x0f, 0x0f, 0x09, 0x09,  +	0x09, 0x00, 0x09, 0x0b, 0x0b, 0x0d, 0x0d, 0x09, 0x00, 0x06, 0x09, 0x09, 0x09, 0x09, 0x06, 0x00,  +	0x07, 0x09, 0x09, 0x07, 0x01, 0x01, 0x00, 0x06, 0x09, 0x09, 0x09, 0x0b, 0x06, 0x08, 0x07, 0x09,  +	0x09, 0x07, 0x05, 0x09, 0x00, 0x06, 0x09, 0x02, 0x04, 0x09, 0x06, 0x00, 0x07, 0x02, 0x02, 0x02,  +	0x02, 0x02, 0x00, 0x09, 0x09, 0x09, 0x09, 0x09, 0x06, 0x00, 0x09, 0x09, 0x09, 0x09, 0x06, 0x06,  +	0x00, 0x09, 0x09, 0x09, 0x0f, 0x0f, 0x09, 0x00, 0x09, 0x09, 0x06, 0x06, 0x09, 0x09, 0x00, 0x05,  +	0x05, 0x05, 0x02, 0x02, 0x02, 0x00, 0x0f, 0x08, 0x04, 0x02, 0x01, 0x0f, 0x00, 0x07, 0x01, 0x01,  +	0x01, 0x01, 0x07, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x00, 0x00, 0x07, 0x04, 0x04, 0x04, 0x04,  +	0x07, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00,  +	0x03, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x09, 0x0d, 0x0a, 0x00, 0x01, 0x01,  +	0x07, 0x09, 0x09, 0x07, 0x00, 0x00, 0x00, 0x06, 0x01, 0x01, 0x06, 0x00, 0x08, 0x08, 0x0e, 0x09,  +	0x09, 0x0e, 0x00, 0x00, 0x00, 0x06, 0x0d, 0x03, 0x06, 0x00, 0x04, 0x0a, 0x02, 0x07, 0x02, 0x02,  +	0x00, 0x00, 0x00, 0x0e, 0x09, 0x06, 0x01, 0x0e, 0x01, 0x01, 0x07, 0x09, 0x09, 0x09, 0x00, 0x02,  +	0x00, 0x03, 0x02, 0x02, 0x07, 0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x05, 0x02, 0x01, 0x01, 0x05,  +	0x03, 0x05, 0x09, 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x07, 0x00, 0x00, 0x00, 0x05, 0x0f, 0x09,  +	0x09, 0x00, 0x00, 0x00, 0x07, 0x09, 0x09, 0x09, 0x00, 0x00, 0x00, 0x06, 0x09, 0x09, 0x06, 0x00,  +	0x00, 0x00, 0x07, 0x09, 0x09, 0x07, 0x01, 0x00, 0x00, 0x0e, 0x09, 0x09, 0x0e, 0x08, 0x00, 0x00,  +	0x07, 0x09, 0x01, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x03, 0x0c, 0x07, 0x00, 0x02, 0x02, 0x07, 0x02,  +	0x02, 0x0c, 0x00, 0x00, 0x00, 0x09, 0x09, 0x09, 0x0e, 0x00, 0x00, 0x00, 0x05, 0x05, 0x05, 0x02,  +	0x00, 0x00, 0x00, 0x09, 0x09, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x09, 0x06, 0x06, 0x09, 0x00, 0x00,  +	0x00, 0x09, 0x09, 0x0a, 0x04, 0x02, 0x00, 0x00, 0x0f, 0x04, 0x02, 0x0f, 0x00, 0x04, 0x02, 0x03,  +	0x02, 0x02, 0x04, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x06, 0x02, 0x02,  +	0x01, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  +	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x04,  +	0x0e, 0x05, 0x05, 0x0e, 0x04, 0x00, 0x0c, 0x02, 0x07, 0x02, 0x0d, 0x00, 0x00, 0x11, 0x0e, 0x0a,  +	0x0e, 0x11, 0x00, 0x05, 0x05, 0x02, 0x07, 0x02, 0x02, 0x00, 0x00, 0x04, 0x04, 0x00, 0x04, 0x04,  +	0x00, 0x0c, 0x02, 0x06, 0x0a, 0x0c, 0x08, 0x06, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e,  +	0x11, 0x15, 0x13, 0x15, 0x11, 0x0e, 0x06, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12,  +	0x09, 0x12, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00,  +	0x00, 0x00, 0x0e, 0x11, 0x17, 0x13, 0x13, 0x11, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  +	0x04, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x1f, 0x04, 0x04, 0x1f, 0x00, 0x06, 0x04,  +	0x02, 0x06, 0x00, 0x00, 0x00, 0x06, 0x06, 0x04, 0x06, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00,  +	0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x09, 0x07, 0x01, 0x0e, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a,  +	0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x04,  +	0x06, 0x04, 0x0e, 0x00, 0x00, 0x00, 0x02, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,  +	0x12, 0x09, 0x00, 0x00, 0x01, 0x01, 0x01, 0x09, 0x0c, 0x0e, 0x08, 0x01, 0x01, 0x01, 0x0d, 0x08,  +	0x04, 0x0c, 0x03, 0x03, 0x02, 0x0b, 0x0c, 0x0e, 0x08, 0x02, 0x00, 0x02, 0x01, 0x05, 0x02, 0x00,  +	0x06, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x00, 0x06, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x00, 0x06, 0x09,  +	0x09, 0x0f, 0x09, 0x09, 0x00, 0x06, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x00, 0x06, 0x09, 0x09, 0x0f,  +	0x09, 0x09, 0x00, 0x06, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x00, 0x0e, 0x05, 0x0d, 0x07, 0x05, 0x0d,  +	0x00, 0x06, 0x09, 0x01, 0x01, 0x09, 0x06, 0x02, 0x0f, 0x01, 0x07, 0x01, 0x01, 0x0f, 0x00, 0x0f,  +	0x01, 0x07, 0x01, 0x01, 0x0f, 0x00, 0x0f, 0x01, 0x07, 0x01, 0x01, 0x0f, 0x00, 0x0f, 0x01, 0x07,  +	0x01, 0x01, 0x0f, 0x00, 0x07, 0x02, 0x02, 0x02, 0x02, 0x07, 0x00, 0x07, 0x02, 0x02, 0x02, 0x02,  +	0x07, 0x00, 0x07, 0x02, 0x02, 0x02, 0x02, 0x07, 0x00, 0x07, 0x02, 0x02, 0x02, 0x02, 0x07, 0x00,  +	0x07, 0x0a, 0x0b, 0x0a, 0x0a, 0x07, 0x00, 0x0d, 0x09, 0x0b, 0x0d, 0x0d, 0x09, 0x00, 0x06, 0x09,  +	0x09, 0x09, 0x09, 0x06, 0x00, 0x06, 0x09, 0x09, 0x09, 0x09, 0x06, 0x00, 0x06, 0x09, 0x09, 0x09,  +	0x09, 0x06, 0x00, 0x06, 0x09, 0x09, 0x09, 0x09, 0x06, 0x00, 0x06, 0x09, 0x09, 0x09, 0x09, 0x06,  +	0x00, 0x00, 0x00, 0x09, 0x06, 0x06, 0x09, 0x00, 0x0e, 0x0d, 0x0d, 0x0b, 0x0b, 0x07, 0x00, 0x09,  +	0x09, 0x09, 0x09, 0x09, 0x06, 0x00, 0x09, 0x09, 0x09, 0x09, 0x09, 0x06, 0x00, 0x09, 0x09, 0x09,  +	0x09, 0x09, 0x06, 0x00, 0x09, 0x09, 0x09, 0x09, 0x09, 0x06, 0x00, 0x05, 0x05, 0x05, 0x02, 0x02,  +	0x02, 0x00, 0x01, 0x07, 0x09, 0x07, 0x01, 0x01, 0x00, 0x06, 0x09, 0x07, 0x09, 0x0b, 0x05, 0x01,  +	0x02, 0x04, 0x0e, 0x09, 0x0d, 0x0a, 0x00, 0x04, 0x02, 0x0e, 0x09, 0x0d, 0x0a, 0x00, 0x04, 0x0a,  +	0x0e, 0x09, 0x0d, 0x0a, 0x00, 0x0a, 0x05, 0x0e, 0x09, 0x0d, 0x0a, 0x00, 0x0a, 0x00, 0x0e, 0x09,  +	0x0d, 0x0a, 0x00, 0x06, 0x06, 0x0e, 0x09, 0x0d, 0x0a, 0x00, 0x00, 0x00, 0x0e, 0x0d, 0x05, 0x0e,  +	0x00, 0x00, 0x00, 0x06, 0x01, 0x01, 0x06, 0x02, 0x02, 0x04, 0x06, 0x0d, 0x03, 0x06, 0x00, 0x04,  +	0x02, 0x06, 0x0d, 0x03, 0x06, 0x00, 0x02, 0x05, 0x06, 0x0d, 0x03, 0x06, 0x00, 0x05, 0x00, 0x06,  +	0x0d, 0x03, 0x06, 0x00, 0x01, 0x02, 0x03, 0x02, 0x02, 0x07, 0x00, 0x02, 0x01, 0x03, 0x02, 0x02,  +	0x07, 0x00, 0x02, 0x05, 0x03, 0x02, 0x02, 0x07, 0x00, 0x05, 0x00, 0x03, 0x02, 0x02, 0x07, 0x00,  +	0x02, 0x0c, 0x06, 0x09, 0x09, 0x06, 0x00, 0x0a, 0x05, 0x07, 0x09, 0x09, 0x09, 0x00, 0x02, 0x04,  +	0x06, 0x09, 0x09, 0x06, 0x00, 0x04, 0x02, 0x06, 0x09, 0x09, 0x06, 0x00, 0x06, 0x00, 0x06, 0x09,  +	0x09, 0x06, 0x00, 0x0a, 0x05, 0x06, 0x09, 0x09, 0x06, 0x00, 0x05, 0x00, 0x06, 0x09, 0x09, 0x06,  +	0x00, 0x00, 0x06, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0e, 0x0d, 0x0b, 0x07, 0x00, 0x02,  +	0x04, 0x09, 0x09, 0x09, 0x0e, 0x00, 0x04, 0x02, 0x09, 0x09, 0x09, 0x0e, 0x00, 0x06, 0x00, 0x09,  +	0x09, 0x09, 0x0e, 0x00, 0x0a, 0x00, 0x09, 0x09, 0x09, 0x0e, 0x00, 0x04, 0x02, 0x09, 0x09, 0x0a,  +	0x04, 0x02, 0x00, 0x01, 0x07, 0x09, 0x09, 0x07, 0x01, 0x0a, 0x00, 0x09, 0x09, 0x0a, 0x04, 0x02,  +}; + +static const uint16_t glyph_pos[256] = { +	   0,    7,   14,   21,   28,   35,   42,   49,  +	  56,   63,   70,   77,   84,   91,   98,  105,  +	 112,  119,  126,  133,  140,  147,  154,  161,  +	 168,  175,  182,  189,  196,  203,  210,  217,  +	 224,  231,  238,  245,  252,  259,  266,  273,  +	 280,  287,  294,  301,  308,  315,  322,  329,  +	 336,  343,  350,  357,  364,  371,  378,  385,  +	 392,  399,  406,  413,  420,  427,  434,  441,  +	 448,  455,  462,  469,  476,  483,  490,  497,  +	 504,  511,  518,  525,  532,  539,  546,  553,  +	 560,  567,  574,  581,  588,  595,  602,  609,  +	 616,  623,  630,  637,  644,  651,  658,  665,  +	 672,  679,  686,  693,  700,  707,  714,  721,  +	 728,  735,  742,  749,  756,  763,  770,  777,  +	 784,  791,  798,  805,  812,  819,  826,  833,  +	 840,  847,  854,  861,  868,  875,  882,  889,  +	   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,    0,    0,    0,    0,    0,    0,  +	 896,  903,  910,  917,  924,  931,  938,  945,  +	 952,  959,  966,  973,  980,  987,  994, 1001,  +	1008, 1015, 1022, 1029, 1036, 1043, 1050, 1057,  +	1064, 1071, 1078, 1085, 1092, 1099, 1106, 1113,  +	1120, 1127, 1134, 1141, 1148, 1155, 1162, 1169,  +	1176, 1183, 1190, 1197, 1204, 1211, 1218, 1225,  +	1232, 1239, 1246, 1253, 1260, 1267, 1274, 1281,  +	1288, 1295, 1302, 1309, 1316, 1323, 1330, 1337,  +	1344, 1351, 1358, 1365, 1372, 1379, 1386, 1393,  +	1400, 1407, 1414, 1421, 1428, 1435, 1442, 1449,  +	1456, 1463, 1470, 1477, 1484, 1491, 1498, 1505,  +	1512, 1519, 1526, 1533, 1540, 1547, 1554, 1561,  +}; + +#define GLYPH_WIDTH 5 +#define GLYPH_HEIGHT 7 +#define GLYPH_ASCENT 6 diff --git a/src/draw/ao_line.c b/src/draw/ao_line.c new file mode 100644 index 00000000..ed1fc21c --- /dev/null +++ b/src/draw/ao_line.c @@ -0,0 +1,314 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include "ao.h" +#include "ao_draw.h" +#include "ao_draw_int.h" + +#define ao_mask(x,w)	(ao_right(AO_ALLONES,(x) & AO_MASK) & \ +			 ao_left(AO_ALLONES,(FB_UNIT - ((x)+(w))) & AO_MASK)) + + +/* out of clip region codes */ +#define OUT_LEFT 0x08 +#define OUT_RIGHT 0x04 +#define OUT_ABOVE 0x02 +#define OUT_BELOW 0x01 + +/* major axis for bresenham's line */ +#define X_AXIS	0 +#define Y_AXIS	1 + +/* + * Line clipping. Clip to the box, bringing the coordinates forward while + * preserving the actual slope and error + * + * + *	X major line, clip X: + * + *	adjust_x = -x; + * + *	e += adjust_x * e1; + * + *	adjust_y = (e + -e3-1) / -e3; + * + *	e -= adjust_y / -e3; + * + *	X major line, clip Y: + * + *	adjust_y = -y; + + * + *	e -= adjust_y / -e3; + * + *	adjust_x = e / e1; + */ + + + + +static void +ao_bres(const struct ao_bitmap	*dst_bitmap, +	int16_t		signdx, +	int16_t		signdy, +	int16_t		axis, +	int16_t		x1, +	int16_t		y1, +	int16_t		e, +	int16_t		e1, +	int16_t		e3, +	int16_t		len, +	uint32_t	and, +	uint32_t	xor) +{ +	int16_t		stride = dst_bitmap->stride; +	uint32_t	*dst = dst_bitmap->base; +	uint32_t	mask0, mask; + +	mask0 = 1; +	if (signdx < 0) +		mask0 = ao_right(1, AO_UNIT - 1); + +	if (signdy < 0) +		stride = -stride; + +	dst = dst + y1 * stride + (x1 >> AO_SHIFT); +	mask = ao_right(1, x1 & AO_MASK); + +	while (len--) { +		/* clip each point */ + +		*dst = ao_do_mask_rrop(*dst, and, xor, mask); + +		if (axis == X_AXIS) { +			if (signdx < 0) +				mask = ao_left(mask, 1); +			else +				mask = ao_right(mask, 1); +			if (!mask) { +				dst += signdx; +				mask = mask0; +			} +			e += e1; +			if (e >= 0) { +				dst += stride; +				e += e3; +			} +		} else { +			dst += stride; +			e += e1; +			if (e >= 0) { +				if (signdx < 0) +					mask = ao_left(mask, 1); +				else +					mask = ao_right(mask, 1); +				if (!mask) { +					dst += signdx; +					mask = mask0; +				} +				e += e3; +			} +		} +	} +} + +struct ao_cc { +	int16_t	major; +	int16_t	minor; +	int16_t	sign_major; +	int16_t	sign_minor; +	int16_t	e; +	int16_t	e1; +	int16_t	e3; +	int8_t	first; +}; + +/* line clipping box */ +struct ao_cbox { +	int16_t	maj1, min1; +	int16_t	maj2, min2; +}; + +/* -b <= a, so we need to make a bigger */ +static int16_t +div_ceil(int32_t a, int16_t b) { +	return (a + b + b - 1) / b - 1; +} + +static int16_t +div_floor_plus_one(int32_t a, int16_t b) { +	return (a + b) / b; +} + +static int8_t +ao_clip_line(struct ao_cc *c, struct ao_cbox *b) +{ +	int32_t	adjust_major = 0, adjust_minor = 0; + +	/* Clip major axis */ +	if (c->major < b->maj1) { +		if (c->sign_major <= 0) +			return FALSE; +		adjust_major = b->maj1 - c->major; +	} else if (c->major >= b->maj2) { +		if (c->sign_major >= 0) +			return FALSE; +		adjust_major = c->major - (b->maj2-1); +	} + +	/* Clip minor axis */ +	if (c->minor < b->min1) { +		if (c->sign_minor <= 0) +			return FALSE; +		adjust_minor = b->min1 - c->minor; +	} else if (c->minor >= b->min2) { +		if (c->sign_minor >= 0) +			return FALSE; +		adjust_minor = c->minor - (b->min2-1); +	} + +	/* If unclipped, we're done */ +	if (adjust_major == 0 && adjust_minor == 0) +		return TRUE; + +	/* See how much minor adjustment would happen during +	 * a major clip. This is a bit tricky because line drawing +	 * isn't symmetrical when the line passes exactly between +	 * two pixels, we have to pick which one gets drawn +	 */ +	int32_t	adj_min; + +	if (!c->first) +		adj_min = div_ceil(c->e + adjust_major * c->e1, -c->e3); +	else +		adj_min = div_floor_plus_one(c->e + adjust_major * c->e1, -c->e3); + +	if (adj_min < adjust_minor) { +		if (c->first) +			adjust_major = div_ceil(c->e - adjust_minor * c->e3, c->e1); +		else +			adjust_major = div_floor_plus_one(c->e - adjust_minor * c->e3, c->e1); +	} else { +		adjust_minor = adj_min; +	} + +	c->e += adjust_major * c->e1 + adjust_minor * c->e3; + +	c->major += c->sign_major * adjust_major; +	c->minor += c->sign_minor * adjust_minor; + +	return TRUE; +} + +void +ao_line(const struct ao_bitmap	*dst, +	int16_t			x1, +	int16_t			y1, +	int16_t			x2, +	int16_t			y2, +	uint32_t		fill, +	uint8_t			rop) +{ +	int16_t	adx, ady; +	int16_t	e, e1, e2, e3; +	int16_t	signdx = 1, signdy = 1; +	int16_t axis; +	int16_t len; +	struct ao_cc	clip_1, clip_2; +	struct ao_cbox	cbox; + +	if ((adx = x2 - x1) < 0) { +		adx = -adx; +		signdx = -1; +	} +	if ((ady = y2 - y1) < 0) { +		ady = -ady; +		signdy = -1; +	} + +	if (adx > ady) { +		axis = X_AXIS; +		e1 = ady << 1; +		e2 = e1 - (adx << 1); +		e = e1 - adx; + +		clip_1.major = x1; +		clip_1.minor = y1; +		clip_2.major = x2; +		clip_2.minor = y2; +		clip_1.sign_major = signdx; +		clip_1.sign_minor = signdy; + +		cbox.maj1 = 0; +		cbox.maj2 = dst->width; +		cbox.min1 = 0; +		cbox.min2 = dst->height; +	} else { +		axis = Y_AXIS; +		e1 = adx << 1; +		e2 = e1 - (ady << 1); +		e = e1 - ady; + +		clip_1.major = y1; +		clip_1.minor = x1; +		clip_2.major = y2; +		clip_2.minor = x2; +		clip_1.sign_major = signdy; +		clip_1.sign_minor = signdx; + +		cbox.maj1 = 0; +		cbox.maj2 = dst->height; +		cbox.min1 = 0; +		cbox.min2 = dst->width; +	} + +	e3 = e2 - e1; +	e = e - e1; + +	clip_1.first = TRUE; +	clip_2.first = FALSE; +	clip_2.e = clip_1.e = e; +	clip_2.e1 = clip_1.e1 = e1; +	clip_2.e3 = clip_1.e3 = e3; +	clip_2.sign_major = -clip_1.sign_major; +	clip_2.sign_minor = -clip_1.sign_minor; + +	if (!ao_clip_line(&clip_1, &cbox)) +		return; + +	if (!ao_clip_line(&clip_2, &cbox)) +		return; + +	len = clip_1.sign_major * (clip_2.major - clip_1.major) + clip_2.first; + +	if (len <= 0) +		return; + +	if (adx > ady) { +		x1 = clip_1.major; +		y1 = clip_1.minor; +	} else { +		x1 = clip_1.minor; +		y1 = clip_1.major; +	} +	ao_bres(dst, +		signdx, +		signdy, +		axis, +		x1, +		y1, +		clip_1.e, e1, e3, len, +		ao_and(rop, fill), +		ao_xor(rop, fill)); +} diff --git a/src/draw/ao_pattern.c b/src/draw/ao_pattern.c new file mode 100644 index 00000000..0d1dc765 --- /dev/null +++ b/src/draw/ao_pattern.c @@ -0,0 +1,80 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include "ao.h" +#include "ao_draw.h" +#include "ao_draw_int.h" + +static inline uint32_t +ao_pattern_expand(uint8_t v, uint8_t rot) +{ +	uint32_t	r; + +	if (rot) +		v = ao_left(v, 8-rot) | ao_right(v, rot); +	r = v; +	return (r << 24) | (r << 16) | (r << 8) | (r); +} + +static inline int +min(int a, int b) { +	return a < b ? a : b; +} + +void +ao_pattern(const struct ao_bitmap	*dst, +	   int16_t			x, +	   int16_t			y, +	   int16_t			width, +	   int16_t			height, +	   const struct ao_pattern	*pattern, +	   int16_t			pat_x, +	   int16_t			pat_y, +	   uint8_t			rop) +{ +	uint32_t	pat[8]; + +	int16_t	x2 = x + width; +	int16_t y2 = y + height; + +	ao_clip(x, 0, dst->width); +	ao_clip(x2, 0, dst->width); +	ao_clip(y, 0, dst->height); +	ao_clip(y2, 0, dst->height); + +	if (x < x2 && y < y2) { +		int	xrot = (x - pat_x) & 7; +		int	yrot = (y - pat_y) & 7; +		int	i; +		int16_t	dst_x, dst_y; + +		for (i = 0; i < 8; i++) +			pat[(i + yrot) & 7] = ao_pattern_expand(pattern->pattern[i], xrot); +		for (dst_y = y; dst_y < y2; dst_y += 8) { +			int	h = min(y2 - dst_y, 8); +			for (dst_x = x; dst_x < x2; dst_x += 8) { +				int	w = min(x2 - dst_x, 8); + +				ao_blt(pat, 1, 0, +				       dst->base + dst_y * dst->stride, +				       dst->stride, +				       dst_x, +				       w, h, +				       rop, +				       0, 0); +			} +		} +	} +} + diff --git a/src/draw/ao_rect.c b/src/draw/ao_rect.c new file mode 100644 index 00000000..71fa4aea --- /dev/null +++ b/src/draw/ao_rect.c @@ -0,0 +1,46 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include "ao.h" +#include "ao_draw.h" +#include "ao_draw_int.h" + +void +ao_rect(const struct ao_bitmap	*dst, +	int16_t			x, +	int16_t			y, +	int16_t			width, +	int16_t			height, +	uint32_t		fill, +	uint8_t			rop) +{ +	int16_t	x2 = x + width; +	int16_t y2 = y + height; + +	ao_clip(x, 0, dst->width); +	ao_clip(x2, 0, dst->width); +	ao_clip(y, 0, dst->height); +	ao_clip(y2, 0, dst->height); + +	if (x < x2 && y < y2) { +		ao_solid(ao_and(rop, fill), +			 ao_xor(rop, fill), +			 dst->base + y * dst->stride, +			 dst->stride, +			 x, +			 x2 - x, +			 y2 - y); +	} +} + diff --git a/src/draw/ao_text.c b/src/draw/ao_text.c new file mode 100644 index 00000000..7ce2a623 --- /dev/null +++ b/src/draw/ao_text.c @@ -0,0 +1,65 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include "ao.h" +#include "ao_draw.h" +#include "ao_draw_int.h" +#include "ao_font.h" + +const struct ao_font ao_font = { +	.width = GLYPH_WIDTH, +	.height = GLYPH_HEIGHT, +	.ascent = GLYPH_ASCENT, +	.descent = GLYPH_HEIGHT - GLYPH_ASCENT, +}; + +void +ao_text(const struct ao_bitmap	*dst, +	int16_t			x, +	int16_t			y, +	char			*string, +	uint32_t		fill, +	uint8_t			rop) +{ +	uint32_t	src[GLYPH_HEIGHT]; +	char		c; +	int		h; + +	struct ao_bitmap	src_bitmap = { +		.base = src, +		.stride = 1, +		.width = GLYPH_WIDTH, +		.height = GLYPH_HEIGHT +	}; + +	y -= GLYPH_ASCENT; + +	rop = (rop & 3) | 0x4; + +	if ((fill&1) == 0) +		rop ^= 3; + +	while ((c = *string++)) { +		const uint8_t	*bytes = &glyph_bytes[glyph_pos[(uint8_t) c]]; + +		for (h = 0; h < GLYPH_HEIGHT; h++) +			src[h] = bytes[h]; + +		ao_copy(dst, +			x, y, GLYPH_WIDTH, GLYPH_HEIGHT, +			&src_bitmap, +			0, 0, rop); +		x += GLYPH_WIDTH; +	} +} diff --git a/src/draw/font-convert b/src/draw/font-convert new file mode 100755 index 00000000..1985e418 --- /dev/null +++ b/src/draw/font-convert @@ -0,0 +1,150 @@ +#!/usr/bin/nickle + +typedef struct { +	int[]	bytes; +	int	width; +	int	height; +	int	encoding; +	int	location; +} glyph_t; + +typedef struct { +	glyph_t[...]	glyphs; +	int		default_char; +	int		ascent; +} font_t; + +glyph_t +read_glyph(file f) +{ +	glyph_t	glyph = { .encoding = -1, .bytes = (int[...]){}, .width = 0 }; + +	while (!File::end(f)) { +		string	l = fgets(f); + +		string[*] tokens = String::split(l, " "); +		if (dim(tokens) == 0) +			continue; + +		switch (tokens[0]) { +		case "ENCODING": +			glyph.encoding = atoi(tokens[1]); +			break; +		case "DWIDTH": +			glyph.width = atoi(tokens[1]); +			break; +		case "BBX": +			glyph.height = atoi(tokens[2]); +			break; +		case "ENDCHAR": +			return glyph; +		case "BITMAP": +			while (!File::end(f)) { +				string l = fgets(f); +				if (l == "ENDCHAR") +					return glyph; +				glyph.bytes[dim(glyph.bytes)] = atoi(l, 16); +			} +			break; +		} +	} +	return glyph; +} + +font_t read_font(file f) { +	font_t	font = { .glyphs = {}, .default_char = -1 }; +	bool in_head = true; + +	while (in_head && !File::end(f)) { +		string l = File::fgets(f); + +		string[*] tokens = String::split(l, " "); +		switch (tokens[0]) { +		case "DEFAULT_CHAR": +			font.default_char = atoi(tokens[1]); +			break; +		case "FONT_ASCENT": +			font.ascent = atoi(tokens[1]); +			break; +		case "CHARS": +			in_head = false; +			break; +		} +	} +	while (!File::end(f)) { +		glyph_t	glyph = read_glyph(f); +		if (glyph.encoding == -1) +			break; +		font.glyphs[dim(font.glyphs)] = glyph; +	} +	return font; +} + +int +flip_byte(int x) +{ +	int	dest = 0; + +	for (int i = 0; i < 8; i++) +		dest |= ((x >> (7 - i)) & 1) << i; +	return dest; +} + +void print_font(font_t font) { +	int	width = font.glyphs[0].width; +	int	height = font.glyphs[0].height; +	int[256] pos = { -1 ... }; +	int[...] bytes; + +	if (false) { +	for (int i = 1; i < dim(font.glyphs); i++) { +		if (font.glyphs[i].width != width || +		   font.glyphs[i].height != height) +		{ +			File::fprintf(stderr, "font not constant size, glyph %d is %dx%d\n", +				      font.glyphs[i].encoding, font.glyphs[i].width, font.glyphs[i].height); +			exit(1); +		} +	} +	} + +	if (font.default_char == -1) +		font.default_char = font.glyphs[0].encoding; + +	/* build byte array */ +	for (int i = 0; i < dim(font.glyphs); i++) { +		pos[font.glyphs[i].encoding] = dim(bytes); +		for (int b = 0; b < dim(font.glyphs[i].bytes); b++) +			bytes[dim(bytes)] = font.glyphs[i].bytes[b]; +	} + +	/* Fill in default glyph */ +	for (int i = 0; i < dim(pos); i++) +		if (pos[i] == -1) +			pos[i] = pos[font.default_char]; + +	printf("static const uint8_t glyph_bytes[%d] = {", dim(bytes)); +	for (int b = 0; b < dim(bytes); b++) { +		if ((b & 15) == 0) +			printf("\n\t"); +		printf("0x%02x, ", flip_byte(bytes[b])); +	} +	printf("\n};\n\n"); + +	printf("static const uint16_t glyph_pos[%d] = {", dim(pos)); +	for (int i = 0; i < dim(pos); i++) { +		if ((i & 7) == 0) +			printf("\n\t"); +		printf("%4d, ", pos[i]); +	} +	printf("\n};\n\n"); + +	printf("#define GLYPH_WIDTH %d\n", width); +	printf("#define GLYPH_HEIGHT %d\n", height); +	printf("#define GLYPH_ASCENT %d\n", font.ascent); +} + +twixt (file f = File::open(argv[1], "r"); File::close(f)) { +       font_t font = read_font(f); +       print_font(font); +} diff --git a/src/draw/line.5c b/src/draw/line.5c new file mode 100644 index 00000000..747768b0 --- /dev/null +++ b/src/draw/line.5c @@ -0,0 +1,389 @@ +#!/usr/bin/nickle + +autoimport Cairo; +autoload PRNG; + +int +sign(int x) +{ +	return x == 0 ? 0 : x < 0 ? -1 : 1; +} + +int X_AXIS = 0; +int Y_AXIS = 1; + +typedef struct { +	int	major; +	int	minor; +	int	sign_major; +	int	sign_minor; +	int	e; +	int	e1; +	int	e3; +	bool	first; +} clip_context; + +typedef struct { +	int	maj1, min1, maj2, min2; +} clip_box; + +typedef struct { +	int	x1, y1, x2, y2; +} box; + +typedef struct { +	int	x, y; +} point; + +typedef struct { +	int	x1, y1, x2, y2; +	box	b; +	point[]	clipped; +	point[]	run; +} test; + +box	bounds = { .x1 = 10, .x2 = 30, .y1 = 10, .y2 = 30 }; + +int +div_ceil(a, b) { +	a += b; +	assert(a >= 0 && b > 0, "bad divide args %d %d\n", a, b); +	return (a + b - 1) // b - 1; +} + +int +div_floor_plus_one(a, b) { +	a += b; +	assert(a >= 0 && b > 0, "bad divide args %d %d\n", a, b); +	return a // b; +} + +bool +clip(*clip_context c, *clip_box b) +{ +	int	adjust_major = 0, adjust_minor = 0; + +	/* Clip major axis */ +	if (c->major < b->maj1) { +		if (c->sign_major <= 0) +			return false; +		adjust_major = b->maj1 - c->major; +	} else if (c->major >= b->maj2) { +		if (c->sign_major >= 0) +			return false; +		adjust_major = c->major - (b->maj2-1); +	} + +	/* Clip minor axis */ +	if (c->minor < b->min1) { +		if (c->sign_minor <= 0) +			return false; +		adjust_minor = b->min1 - c->minor; +	} else if (c->minor >= b->min2) { +		if (c->sign_minor >= 0) +			return false; +		adjust_minor = c->minor - (b->min2-1); +	} + +	/* If unclipped, we're done */ +	if (adjust_major == 0 && adjust_minor == 0) +		return true; + +	/* See how much minor adjustment would happen during +	 * a major clip. This is a bit tricky because line drawing +	 * isn't symmetrical when the line passes exactly between +	 * two pixels, we have to pick which one gets drawn +	 */ +	int	adj_min; + +	if (!c->first) +		adj_min = div_ceil(c->e + adjust_major * c->e1, -c->e3); +	else +		adj_min = div_floor_plus_one(c->e + adjust_major * c->e1, -c->e3); + +	/* Compare that to the minor clip and pick +	 * the larger amount. +	 */ +	printf ("\tinitial major %d minor %d error %d e1 %d e3 %d\n", c->major, c->minor, c->e, c->e1, c->e3); + +	if (adj_min < adjust_minor) { +		printf("\tminor clip dominates %d < %d. adjust major %d -> ", +		       adj_min, adjust_minor, adjust_major); +		if (c->first) +			adjust_major = div_ceil(c->e - adjust_minor * c->e3, c->e1); +		else +			adjust_major = div_floor_plus_one(c->e - adjust_minor * c->e3, c->e1); +		printf("%d\n", adjust_major); +	} else { +		printf("\tminor clip dominates %d > %d. adjust minor %d -> ", +		       adj_min, adjust_minor, adjust_minor); +		adjust_minor = adj_min; +		printf("%d\n", adjust_minor); +	} + +	c->e += adjust_major * c->e1 + adjust_minor * c->e3; + +	c->major += c->sign_major * adjust_major; +	c->minor += c->sign_minor * adjust_minor; + +	printf ("\tadjust major %d adjust minor %d e %d e1 %d e3 %e\n", +		adjust_major, adjust_minor, c->e, c->e1, c->e3); + +	if (c->e >= 0) +		printf ("error positive e %d e1 %d e3 %d\n", +			c->e, c->e1, c->e3); +	if (c->e < c->e3) +		printf ("error magnitude too large e %d e1 %d e3 %d\n", c->e, c->e1, c->e3); + +	return true; +} + +test +line(int x1, int y1, int x2, int y2, *box b) { + +	int	dx = x2 - x1; +	int	dy = y2 - y1; +	int	signdx = sign(dx); +	int	signdy = sign(dy); +	int	adx = abs(dx); +	int	ady = abs(dy); +	int	axis; +	int	e, e1, e2, e3; +	int	len; +	clip_context	clip_1, clip_2; +	clip_box	c; +	bool		clipped = false; +	test		t = { +		.x1 = x1, +		.y1 = y1, +		.x2 = x2, +		.y2 = y2, +		.b = *b, +		.clipped = (point[...]) {}, +		.run = (point[...]) {} +	}; + +	if (adx >= ady) { +		axis = X_AXIS; +		e1 = ady << 1; +		e2 = e1 - (adx << 1); +		e = e1 - adx; +		len = adx; + +		clip_1.major = x1; +		clip_1.minor = y1; +		clip_2.major = x2; +		clip_2.minor = y2; +		clip_1.sign_major = signdx; +		clip_1.sign_minor = signdy; + +		c.maj1 = b->x1; +		c.maj2 = b->x2; +		c.min1 = b->y1; +		c.min2 = b->y2; +	} else { +		axis = Y_AXIS; +		e1 = adx << 1; +		e2 = e1 - (ady << 1); +		e = e1 - ady; +		len = ady; + +		clip_1.major = y1; +		clip_1.minor = x1; +		clip_2.major = y2; +		clip_2.minor = x2; +		clip_1.sign_major = signdy; +		clip_1.sign_minor = signdx; +		c.maj1 = b->y1; +		c.maj2 = b->y2; +		c.min1 = b->x1; +		c.min2 = b->x2; +	} + +	e3 = e2 - e1; +	e = e - e1; + +	clip_1.first = true; +	clip_2.first = false; +	clip_2.e = clip_1.e = e; +	clip_2.e1 = clip_1.e1 = e1; +	clip_2.e3 = clip_1.e3 = e3; +	clip_2.sign_major = -clip_1.sign_major; +	clip_2.sign_minor = -clip_1.sign_minor; + +	printf ("clip start:\n"); +	if (!clip(&clip_1, &c)) +		clipped = true; + +	printf("clip end:\n"); +	if (!clip(&clip_2, &c)) +		clipped = true; + +	int	clip_len; +	int	clip_x, clip_y; +	int	clip_e; +	int	x_major, x_minor; +	int	y_major, y_minor; + +	clip_len = clip_1.sign_major * (clip_2.major - clip_1.major); +	if (clip_len < 0) +		clipped = true; + +	int x, y; + +	if (axis == X_AXIS) { +		x = clip_1.major; +		y = clip_1.minor; +		x_major = clip_1.sign_major; +		x_minor = 0; +		y_major = 0; +		y_minor = clip_1.sign_minor; +	} else { +		x = clip_1.minor; +		y = clip_1.major; +		x_major = 0; +		x_minor = clip_1.sign_minor; +		y_major = clip_1.sign_major; +		y_minor = 0; +	} + +	clip_e = clip_1.e; + +	if (clipped) +		clip_len = -1; + +	while (clip_len-- >= 0) { +		t.clipped[dim(t.clipped)] = (point) { .x = x, .y = y }; +		x += x_major; +		y += y_major; +		clip_e += e1; +		if (clip_e >= 0) { +			x += x_minor; +			y += y_minor; +			clip_e += e3; +		} +	} + +	x = x1; +	y = y1; + +	while (len-- >= 0) { +		if (bounds.x1 <= x && x < bounds.x2 && +		    bounds.y1 <= y && y < bounds.y2) { +			t.run[dim(t.run)] = (point) { .x = x, .y = y }; +		} +		x += x_major; +		y += y_major; +		e += e1; +		if (e >= 0) { +			x += x_minor; +			y += y_minor; +			e += e3; +		} +	} +	return t; +} + +void read_events (Cairo::cairo_t cr) +{ +	file	event = Cairo::open_event(cr); + +	while (!File::end(event)) { +		string	event_line = File::fgets(event); +		if (String::index(event_line, "delete") >= 0) +			exit(0); +	} +} + +#for (int y = 0; y < 20; y++) + +void +show(cairo_t cr, test t) +{ +	rectangle(cr, 0, 0, 40, 40); +	set_source_rgba(cr, 1, 1, 1, 1); +	fill(cr); + +	set_source_rgba(cr, 0, 1, 0, .2); +	set_line_width(cr, 0.1); +	for (int x = 0; x < 40; x++) { +		move_to(cr, 0, x); +		line_to(cr, 40, x); +		move_to(cr, x, 0); +		line_to(cr, x, 40); +	} +	stroke(cr); + +	rectangle(cr, t.b.x1, t.b.y1, t.b.x2 - t.b.x1, t.b.y2 - t.b.y1); +	set_line_width(cr, 0.1); +	set_source_rgba(cr, 0, 0, 0, 1); +	stroke(cr); + +	move_to(cr, t.x1+.5, t.y1+.5); +	line_to(cr, t.x2+.5, t.y2+.5); +	move_to(cr, t.x2, t.y2); +	line_to(cr, t.x2+1, t.y2+1); +	move_to(cr, t.x2+1, t.y2); +	line_to(cr, t.x2, t.y2+1); +	stroke(cr); + +	void pixels(point[] pt) { +		for (int i = 0; i < dim(pt); i++) { +			rectangle(cr, pt[i].x, pt[i].y, 1, 1); +		} +		fill(cr); +	} + +	set_source_rgba(cr, 1, 0, 0, .5); +	pixels(t.clipped); + +	set_source_rgba(cr, 0, 0, 1, .5); +	pixels(t.run); +} + +bool +compare(test t) +{ +	if (dim(t.clipped) != dim(t.run)) +		return false; + +	for (int i = 0; i < dim(t.clipped); i++) +		if (t.clipped[i] != t.run[i]) +			return false; +	return true; +} + +void +doit(int i) +{ +	int	n; +	*box	b = &bounds; + +	cairo_t cr = new(800, 800); + +	scale(cr, 20, 20); + +	for (;;) { +		PRNG::srandom(i); +		int	x1 = PRNG::randint(40); +		int	x2 = PRNG::randint(40); +		int	y1 = PRNG::randint(40); +		int	y2 = PRNG::randint(40); + +		test t = line (x1, y1, x2, y2, &bounds); +		show(cr, t); +		if (!compare(t)) { +			printf("line %d -- %d x %d - %d x %d\n", i, x1, y1, x2, y2); +			gets(); +		} +		i++; +	} + +	read_events(cr); +} + +int i = 0; +if (dim(argv) > 1) +	i = atoi(argv[1]); + +doit(i); diff --git a/src/drivers/ao_as1107.c b/src/drivers/ao_as1107.c new file mode 100644 index 00000000..e0172d95 --- /dev/null +++ b/src/drivers/ao_as1107.c @@ -0,0 +1,105 @@ +/* + * Copyright © 2017 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <ao.h> +#include <ao_as1107.h> + +static uint8_t	as1107_configured; +static uint8_t	as1107_mutex; + +static void +ao_as1107_start(void) { +	ao_spi_get_bit(AO_AS1107_CS_PORT, AO_AS1107_CS_PIN, AO_AS1107_CS, AO_AS1107_SPI_INDEX, AO_AS1107_SPI_SPEED); +} + +static void +ao_as1107_stop(void) { +	ao_spi_put_bit(AO_AS1107_CS_PORT, AO_AS1107_CS_PIN, AO_AS1107_CS, AO_AS1107_SPI_INDEX); +} + +static void +_ao_as1107_cmd(uint8_t addr, uint8_t value) +{ +	uint8_t	packet[2] = { addr, value }; + +	ao_as1107_start(); +	ao_spi_send(packet, 2, AO_AS1107_SPI_INDEX); +	ao_as1107_stop(); +} + +static void +_ao_as1107_setup(void) +{ +	if (!as1107_configured) { +		as1107_configured = 1; +		_ao_as1107_cmd(AO_AS1107_SHUTDOWN, AO_AS1107_SHUTDOWN_SHUTDOWN_RESET); +		_ao_as1107_cmd(AO_AS1107_SHUTDOWN, AO_AS1107_SHUTDOWN_SHUTDOWN_NOP); +		_ao_as1107_cmd(AO_AS1107_DECODE_MODE, AO_AS1107_DECODE); +		_ao_as1107_cmd(AO_AS1107_SCAN_LIMIT, AO_AS1107_NUM_DIGITS - 1); +		_ao_as1107_cmd(AO_AS1107_INTENSITY, 0x0f); +		_ao_as1107_cmd(AO_AS1107_FEATURE, +			       (0 << AO_AS1107_FEATURE_CLK_EN) | +			       (0 << AO_AS1107_FEATURE_REG_RES) | +			       (1 << AO_AS1107_FEATURE_DECODE_SEL) | +			       (1 << AO_AS1107_FEATURE_SPI_EN) | +			       (0 << AO_AS1107_FEATURE_BLINK_EN) | +			       (0 << AO_AS1107_FEATURE_BLINK_FREQ) | +			       (0 << AO_AS1107_FEATURE_SYNC) | +			       (0 << AO_AS1107_FEATURE_BLINK_START)); +		_ao_as1107_cmd(AO_AS1107_SHUTDOWN, AO_AS1107_SHUTDOWN_NORMAL_NOP); +	} +} + +void +ao_as1107_write(uint8_t start, uint8_t count, uint8_t *values) +{ +	uint8_t i; +	ao_mutex_get(&as1107_mutex); +	_ao_as1107_setup(); +	for (i = 0; i < count; i++) +	{ +		_ao_as1107_cmd(AO_AS1107_DIGIT(start + i), +			       values[i]); +	} +	ao_mutex_put(&as1107_mutex); +} + +void +ao_as1107_write_8(uint8_t start, uint8_t value) +{ +	uint8_t	values[2]; + +	values[0] = (value >> 4); +	values[1] = value & 0xf; +	ao_as1107_write(start, 2, values); +} + +void +ao_as1107_write_16(uint8_t start, uint16_t value) +{ +	uint8_t	values[4]; + +	values[0] = (value >> 12); +	values[1] = (value >> 8) & 0xf; +	values[2] = (value >> 4) & 0xf; +	values[3] = (value) & 0xf; +	ao_as1107_write(start, 4, values); +} + +void +ao_as1107_init(void) +{ +	as1107_configured = 0; +	ao_spi_init_cs(AO_AS1107_CS_PORT, (1 << AO_AS1107_CS_PIN)); +} diff --git a/src/drivers/ao_as1107.h b/src/drivers/ao_as1107.h new file mode 100644 index 00000000..a22b17db --- /dev/null +++ b/src/drivers/ao_as1107.h @@ -0,0 +1,59 @@ +/* + * Copyright © 2017 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef _AO_AS1107_H_ +#define _AO_AS1107_H_ + +#define AO_AS1107_NO_OP		0x00 +#define AO_AS1107_DIGIT(n)	(0x01 + (n)) +#define AO_AS1107_DECODE_MODE	0x09 +#define AO_AS1107_INTENSITY	0x0a +#define AO_AS1107_SCAN_LIMIT	0x0b +#define AO_AS1107_SHUTDOWN	0x0c +#define  AO_AS1107_SHUTDOWN_SHUTDOWN_RESET	0x00 +#define  AO_AS1107_SHUTDOWN_SHUTDOWN_NOP	0x80 +#define  AO_AS1107_SHUTDOWN_NORMAL_RESET	0x01 +#define  AO_AS1107_SHUTDOWN_NORMAL_NOP		0x81 + +#define AO_AS1107_FEATURE	0x0e +#define  AO_AS1107_FEATURE_CLK_EN	0	/* external clock enable */ +#define  AO_AS1107_FEATURE_REG_RES	1 +#define  AO_AS1107_FEATURE_DECODE_SEL	2	/* select HEX decode */ +#define  AO_AS1107_FEATURE_SPI_EN	3 +#define  AO_AS1107_FEATURE_BLINK_EN	4 +#define  AO_AS1107_FEATURE_BLINK_FREQ	5 +#define  AO_AS1107_FEATURE_SYNC		6 +#define  AO_AS1107_FEATURE_BLINK_START	7 +#define AO_AS1107_DISPLAY_TEST	0x0f + +void ao_as1107_init(void); + +void +ao_as1107_write(uint8_t start, uint8_t count, uint8_t *values); + +void +ao_as1107_write_8(uint8_t start, uint8_t value); + +void +ao_as1107_write_16(uint8_t start, uint16_t value); + +#ifndef AO_AS1107_DECODE +#error "must define AO_AS1107_DECODE" +#endif + +#ifndef AO_AS1107_NUM_DIGITS +#error "must define AO_AS1107_NUM_DIGITS" +#endif + +#endif /* _AO_AS1107_H_ */ diff --git a/src/drivers/ao_button.c b/src/drivers/ao_button.c index 725ac45a..07e92c67 100644 --- a/src/drivers/ao_button.c +++ b/src/drivers/ao_button.c @@ -39,8 +39,16 @@ static struct ao_button_state	ao_button_state[AO_BUTTON_COUNT];  #define bit(q) AO_BUTTON_ ## q  #define pin(q) AO_BUTTON_ ## q ## _PIN +#ifndef AO_BUTTON_INVERTED +#define AO_BUTTON_INVERTED	1 +#endif + +#if AO_BUTTON_INVERTED  /* pins are inverted */  #define ao_button_value(b)	!ao_gpio_get(port(b), bit(b), pin(b)) +#else +#define ao_button_value(b)	ao_gpio_get(port(b), bit(b), pin(b)) +#endif  static uint8_t  _ao_button_get(uint8_t b) diff --git a/src/drivers/ao_cc115l.c b/src/drivers/ao_cc115l.c index a67071d2..c1c21e0d 100644 --- a/src/drivers/ao_cc115l.c +++ b/src/drivers/ao_cc115l.c @@ -39,7 +39,7 @@ static uint8_t ao_radio_abort;		/* radio operation should abort */  #define FOSC	26000000 -#define ao_radio_select()	ao_spi_get_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS,AO_SPI_SPEED_6MHz) +#define ao_radio_select()	ao_spi_get_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS,AO_CC115L_SPI_SPEED)  #define ao_radio_deselect()	ao_spi_put_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS)  #define ao_radio_spi_send(d,l)	ao_spi_send((d), (l), AO_CC115L_SPI_BUS)  #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC115L_SPI_BUS) diff --git a/src/drivers/ao_cc1200.c b/src/drivers/ao_cc1200.c index 2bc99734..de282000 100644 --- a/src/drivers/ao_cc1200.c +++ b/src/drivers/ao_cc1200.c @@ -51,7 +51,11 @@ extern const uint32_t	ao_radio_cal;  #define FOSC	40000000  #endif -#define ao_radio_select()	ao_spi_get_mask(AO_CC1200_SPI_CS_PORT,(1 << AO_CC1200_SPI_CS_PIN),AO_CC1200_SPI_BUS,AO_SPI_SPEED_FAST) +#ifndef AO_CC1200_SPI_SPEED +#error AO_CC1200_SPI_SPEED undefined +#endif + +#define ao_radio_select()	ao_spi_get_mask(AO_CC1200_SPI_CS_PORT,(1 << AO_CC1200_SPI_CS_PIN),AO_CC1200_SPI_BUS,AO_CC1200_SPI_SPEED)  #define ao_radio_deselect()	ao_spi_put_mask(AO_CC1200_SPI_CS_PORT,(1 << AO_CC1200_SPI_CS_PIN),AO_CC1200_SPI_BUS)  #define ao_radio_spi_send(d,l)	ao_spi_send((d), (l), AO_CC1200_SPI_BUS)  #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC1200_SPI_BUS) @@ -1323,7 +1327,7 @@ static void ao_radio_packet(void) {  void  ao_radio_test_recv(void)  { -	uint8_t	bytes[34]; +	static uint8_t	bytes[34];  	uint8_t	b;  	if (ao_radio_recv(bytes, 34, 0)) { diff --git a/src/drivers/ao_console.c b/src/drivers/ao_console.c new file mode 100644 index 00000000..cbde38c9 --- /dev/null +++ b/src/drivers/ao_console.c @@ -0,0 +1,151 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include "ao.h" +#include "ao_console.h" +#include "ao_ps2.h" +#include "ao_vga.h" + +static uint8_t	console_row, console_col; + +#define ao_console_bitmap	ao_vga_bitmap + +static uint8_t	console_rows, console_cols; + +static void +ao_console_scroll(void) +{ +	ao_copy(&ao_console_bitmap, +		0, 0, +		ao_console_bitmap.width, +		ao_console_bitmap.height - ao_font.height, +		&ao_console_bitmap, +		0, ao_font.height, +		AO_COPY); +	ao_rect(&ao_console_bitmap, +		0, +		(console_rows - 1) * ao_font.height, +		ao_console_bitmap.width, +		ao_font.height, +		1, +		AO_COPY); +} + +static void +ao_console_cursor(void) +{ +	ao_rect(&ao_console_bitmap, +		console_col * ao_font.width, +		console_row * ao_font.height, +		ao_font.width, +		ao_font.height, +		1, +		AO_XOR); +} + +static void +ao_console_clear(void) +{ +	ao_rect(&ao_console_bitmap, +		0, 0, +		ao_console_bitmap.width, +		ao_console_bitmap.height, +		1, +		AO_COPY); +} + +static void +ao_console_space(void) +{ +	ao_rect(&ao_console_bitmap, +		console_col * ao_font.width, +		console_row * ao_font.height, +		ao_font.width, +		ao_font.height, +		1, +		AO_COPY); +} + +static void +ao_console_newline(void) +{ +	if (++console_row == console_rows) { +		ao_console_scroll(); +		console_row--; +	} +} + +void +ao_console_putchar(char c) +{ +	if (' ' <= c && c < 0x7f) { +		char	text[2]; +		ao_console_space(); +		text[0] = c; +		text[1] = '\0'; +		ao_text(&ao_console_bitmap, +			console_col * ao_font.width, +			console_row * ao_font.height + ao_font.ascent, +			text, +			0, +			AO_COPY); +		if (++console_col == console_cols) { +			console_col = 0; +			ao_console_newline(); +		} +	} else { +		ao_console_cursor(); +		switch (c) { +		case '\r': +			console_col = 0; +			break; +		case '\t': +			console_col += 8 - (console_col & 7); +			if (console_col >= console_cols) { +				console_col = 0; +				ao_console_newline(); +			} +			break; +		case '\n': +			ao_console_newline(); +			break; +		case '\f': +			console_col = console_row = 0; +			ao_console_clear(); +			break; +		case '\177': +		case '\010': +			if (console_col) +				console_col--; +			break; +		} +	} +	ao_console_cursor(); +} + +void +ao_console_init(void) +{ +	console_cols = ao_console_bitmap.width / ao_font.width; +	console_rows = ao_console_bitmap.height / ao_font.height; +#if CONSOLE_STDIN +	ao_ps2_stdin = 1; +	ao_add_stdio(_ao_ps2_pollchar, +		     ao_console_putchar, +		     NULL); +#endif +	ao_console_clear(); +	ao_console_cursor(); +	ao_vga_enable(1); +} diff --git a/src/drivers/ao_console.h b/src/drivers/ao_console.h new file mode 100644 index 00000000..33d3658a --- /dev/null +++ b/src/drivers/ao_console.h @@ -0,0 +1,24 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef _AO_CONSOLE_H_ +#define _AO_CONSOLE_H_ + +void +ao_console_putchar(char c); + +void +ao_console_init(void); + +#endif /* _AO_CONSOLE_H_ */ diff --git a/src/drivers/ao_event.h b/src/drivers/ao_event.h index d1c69d81..d1df6eac 100644 --- a/src/drivers/ao_event.h +++ b/src/drivers/ao_event.h @@ -22,6 +22,7 @@  #define AO_EVENT_NONE		0  #define AO_EVENT_QUADRATURE	1  #define AO_EVENT_BUTTON		2 +#define AO_EVENT_KEY		3  struct ao_event {  	uint8_t		type; diff --git a/src/drivers/ao_fat.c b/src/drivers/ao_fat.c index fb8eecff..43e7df23 100644 --- a/src/drivers/ao_fat.c +++ b/src/drivers/ao_fat.c @@ -1615,7 +1615,7 @@ ao_fat_hexdump_cmd(void)  		ao_cmd_status = ao_cmd_syntax_error;  		return;  	} -		 +  	fd = ao_fat_open(name, AO_FAT_OPEN_READ);  	if (fd < 0) {  		printf ("Open failed: %d\n", fd); @@ -1649,5 +1649,7 @@ void  ao_fat_init(void)  {  	ao_bufio_init(); +#if FAT_COMMANDS  	ao_cmd_register(&ao_fat_cmds[0]); +#endif  } diff --git a/src/drivers/ao_lco.c b/src/drivers/ao_lco.c index 00f10ecc..e1806ca3 100644 --- a/src/drivers/ao_lco.c +++ b/src/drivers/ao_lco.c @@ -661,7 +661,7 @@ ao_lco_monitor(void)  		       ao_lco_armed, ao_lco_firing);  		if (ao_lco_armed && ao_lco_firing) { -			ao_lco_ignite(); +			ao_lco_ignite(AO_PAD_FIRE);  		} else {  			ao_lco_update();  			if (ao_lco_armed) { diff --git a/src/drivers/ao_lco_cmd.c b/src/drivers/ao_lco_cmd.c index dcc0c6d0..8de21fb6 100644 --- a/src/drivers/ao_lco_cmd.c +++ b/src/drivers/ao_lco_cmd.c @@ -61,9 +61,9 @@ lco_arm(void)  }  static void -lco_ignite(void) +lco_ignite(uint8_t cmd)  { -	ao_lco_ignite(); +	ao_lco_ignite(cmd);  }  static void @@ -145,7 +145,40 @@ lco_fire_cmd(void) __reentrant  		secs = 100;  	for (i = 0; i < secs; i++) {  		printf("fire %d\n", i); flush(); -		lco_ignite(); +		lco_ignite(AO_PAD_FIRE); +		ao_delay(AO_MS_TO_TICKS(100)); +	} +} + +static void +lco_static_cmd(void) __reentrant +{ +	uint8_t		secs; +	uint8_t		i; +	int8_t		r; + +	lco_args(); +	ao_cmd_decimal(); +	secs = ao_cmd_lex_i; +	if (ao_cmd_status != ao_cmd_success) +		return; +	r = lco_query(); +	if (r != AO_RADIO_CMAC_OK) { +		printf("query failed %d\n", r); +		return; +	} + +	for (i = 0; i < 4; i++) { +		printf("arm %d\n", i); flush(); +		lco_arm(); +	} + +	secs = secs * 10 - 5; +	if (secs > 100) +		secs = 100; +	for (i = 0; i < secs; i++) { +		printf("fire %d\n", i); flush(); +		lco_ignite(AO_PAD_STATIC);  		ao_delay(AO_MS_TO_TICKS(100));  	}  } @@ -171,12 +204,22 @@ lco_ignite_cmd(void) __reentrant  	uint8_t i;  	lco_args();  	for (i = 0; i < 4; i++) -		lco_ignite(); +		lco_ignite(AO_PAD_FIRE); +} + + +static void +lco_endstatic_cmd(void) __reentrant +{ +	lco_ignite(AO_PAD_ENDSTATIC);  }  static __code struct ao_cmds ao_lco_cmds[] = {  	{ lco_report_cmd,	"l <box> <channel>\0Get remote status" },  	{ lco_fire_cmd,		"F <box> <channel> <secs>\0Fire remote igniters" }, +	{ lco_fire_cmd,		"F <box> <channel> <secs>\0Fire remote igniters" }, +	{ lco_static_cmd,	"S <box> <channel> <secs>\0Initiate static test" }, +	{ lco_endstatic_cmd,	"D\0End static test (and download someday)" },  	{ lco_arm_cmd,		"a <box> <channel>\0Arm remote igniter" },  	{ lco_ignite_cmd,	"i <box> <channel>\0Pulse remote igniter" },  	{ 0, NULL }, diff --git a/src/drivers/ao_lco_func.c b/src/drivers/ao_lco_func.c index 862cb1be..92b344ed 100644 --- a/src/drivers/ao_lco_func.c +++ b/src/drivers/ao_lco_func.c @@ -47,7 +47,7 @@ ao_lco_query(uint16_t box, struct ao_pad_query *query, uint16_t *tick_offset)  	ao_mutex_get(&ao_lco_mutex);  	command.tick = ao_time();  	command.box = box; -	command.cmd = AO_LAUNCH_QUERY; +	command.cmd = AO_PAD_QUERY;  	command.channels = 0;  	ao_radio_cmac_send(&command, sizeof (command));  	sent_time = ao_time(); @@ -64,19 +64,19 @@ ao_lco_arm(uint16_t box, uint8_t channels, uint16_t tick_offset)  	ao_mutex_get(&ao_lco_mutex);  	command.tick = ao_time() - tick_offset;  	command.box = box; -	command.cmd = AO_LAUNCH_ARM; +	command.cmd = AO_PAD_ARM;  	command.channels = channels;  	ao_radio_cmac_send(&command, sizeof (command));  	ao_mutex_put(&ao_lco_mutex);  }  void -ao_lco_ignite(void) +ao_lco_ignite(uint8_t cmd)  {  	ao_mutex_get(&ao_lco_mutex);  	command.tick = 0;  	command.box = 0; -	command.cmd = AO_LAUNCH_FIRE; +	command.cmd = cmd;  	command.channels = 0;  	ao_radio_cmac_send(&command, sizeof (command));  	ao_mutex_put(&ao_lco_mutex); diff --git a/src/drivers/ao_lco_func.h b/src/drivers/ao_lco_func.h index 6b06f928..9d4a27ba 100644 --- a/src/drivers/ao_lco_func.h +++ b/src/drivers/ao_lco_func.h @@ -28,6 +28,6 @@ void  ao_lco_arm(uint16_t box, uint8_t channels, uint16_t tick_offset);  void -ao_lco_ignite(void); +ao_lco_ignite(uint8_t cmd);  #endif /* _AO_LCO_FUNC_H_ */ diff --git a/src/drivers/ao_lco_two.c b/src/drivers/ao_lco_two.c index 1cb0546c..e2f86745 100644 --- a/src/drivers/ao_lco_two.c +++ b/src/drivers/ao_lco_two.c @@ -287,7 +287,7 @@ ao_lco_monitor(void)  		       ao_lco_armed, ao_lco_firing);  		if (ao_lco_armed && ao_lco_firing) { -			ao_lco_ignite(); +			ao_lco_ignite(AO_PAD_FIRE);  		} else {  			ao_lco_get_channels();  			if (ao_lco_armed) { diff --git a/src/drivers/ao_matrix.c b/src/drivers/ao_matrix.c new file mode 100644 index 00000000..fa2d0c57 --- /dev/null +++ b/src/drivers/ao_matrix.c @@ -0,0 +1,201 @@ +/* + * Copyright © 2017 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <ao.h> +#include <ao_matrix.h> +#include <ao_event.h> +#include <ao_exti.h> + +#define row_port(q)	AO_MATRIX_ROW_ ## q ## _PORT +#define row_bit(q) 	AO_MATRIX_ROW_ ## q ## _PIN +#define row_pin(q) 	AO_MATRIX_ROW_ ## q ## _PIN + +#define col_port(q)	AO_MATRIX_COL_ ## q ## _PORT +#define col_bit(q) 	AO_MATRIX_COL_ ## q ## _PIN +#define col_pin(q) 	AO_MATRIX_COL_ ## q ## _PIN + +static void +_ao_matrix_drive_row(uint8_t row, uint8_t val) +{ +	switch (row) { +#define drive(n) case n: ao_gpio_set(row_port(n), row_bit(n), row_pin(n), val); break +		drive(0); +#if AO_MATRIX_ROWS > 1 +		drive(1); +#endif +#if AO_MATRIX_ROWS > 2 +		drive(2); +#endif +#if AO_MATRIX_ROWS > 3 +		drive(3); +#endif +#if AO_MATRIX_ROWS > 4 +		drive(4); +#endif +#if AO_MATRIX_ROWS > 5 +		drive(5); +#endif +#if AO_MATRIX_ROWS > 6 +		drive(6); +#endif +#if AO_MATRIX_ROWS > 7 +		drive(7); +#endif +	} +} + +static uint8_t +_ao_matrix_read_cols(void) +{ +	uint8_t	v = 0; +#define read(n)	(v |= ao_gpio_get(col_port(n), col_bit(n), col_pin(n)) << n) + +	read(0); +#if AO_MATRIX_ROWS > 1 +	read(1); +#endif +#if AO_MATRIX_ROWS > 2 +	read(2); +#endif +#if AO_MATRIX_ROWS > 3 +	read(3); +#endif +#if AO_MATRIX_ROWS > 4 +	read(4); +#endif +#if AO_MATRIX_ROWS > 5 +	read(5); +#endif +#if AO_MATRIX_ROWS > 6 +	read(6); +#endif +#if AO_MATRIX_ROWS > 7 +	read(7); +#endif +	return v; +} + +static uint8_t +_ao_matrix_read(uint8_t row) { +	uint8_t	state; +	_ao_matrix_drive_row(row, 0); +	state = _ao_matrix_read_cols(); +	_ao_matrix_drive_row(row, 1); +	return state; +} + +#define AO_MATRIX_DEBOUNCE_INTERVAL	AO_MS_TO_TICKS(50) + +static uint8_t ao_matrix_keymap[AO_MATRIX_ROWS][AO_MATRIX_COLS] = AO_MATRIX_KEYCODES; + +static uint8_t		ao_matrix_state[AO_MATRIX_ROWS]; +static AO_TICK_TYPE	ao_matrix_tick[AO_MATRIX_ROWS]; + +static void +_ao_matrix_poll_one(uint8_t row) { +	uint8_t	state = _ao_matrix_read(row); + +	if (state != ao_matrix_state[row]) { +		AO_TICK_TYPE	now = ao_time(); + +		if ((now - ao_matrix_tick[row]) >= AO_MATRIX_DEBOUNCE_INTERVAL) { +			uint8_t col; +			uint8_t changes = state ^ ao_matrix_state[row]; + +			for (col = 0; col < AO_MATRIX_COLS; col++) { +				if (changes & (1 << col)) { +					ao_event_put_isr(AO_EVENT_KEY, +							 ao_matrix_keymap[row][col], +							 ((state >> col) & 1) == 0); +				} +			} +			ao_matrix_state[row] = state; +		} +		ao_matrix_tick[row] = now; +	} +} + +void +ao_matrix_poll(void) +{ +	uint8_t	row; + +	for (row = 0; row < AO_MATRIX_ROWS; row++) +		_ao_matrix_poll_one(row); +} + +#define init_row(b) do {						\ +		ao_enable_output(row_port(b), row_bit(b), row_pin(v), 1); \ +		ao_gpio_set_output_mode(row_port(b), row_bit(b), row_pin(b), AO_OUTPUT_OPEN_DRAIN); \ +	} while (0) + +#define init_col(b) do { \ +		ao_enable_input(col_port(b), col_bit(b), AO_EXTI_MODE_PULL_UP); \ +	} while(0) + +void +ao_matrix_init(void) +{ +	uint8_t	row; + +	init_row(0); +#if AO_MATRIX_ROWS > 1 +	init_row(1); +#endif +#if AO_MATRIX_ROWS > 2 +	init_row(2); +#endif +#if AO_MATRIX_ROWS > 3 +	init_row(3); +#endif +#if AO_MATRIX_ROWS > 4 +	init_row(4); +#endif +#if AO_MATRIX_ROWS > 5 +	init_row(5); +#endif +#if AO_MATRIX_ROWS > 6 +	init_row(6); +#endif +#if AO_MATRIX_ROWS > 7 +	init_row(7); +#endif + +	init_col(0); +#if AO_MATRIX_COLS > 1 +	init_col(1); +#endif +#if AO_MATRIX_COLS > 2 +	init_col(2); +#endif +#if AO_MATRIX_COLS > 3 +	init_col(3); +#endif +#if AO_MATRIX_COLS > 4 +	init_col(4); +#endif +#if AO_MATRIX_COLS > 5 +	init_col(5); +#endif +#if AO_MATRIX_COLS > 6 +	init_col(6); +#endif +#if AO_MATRIX_COLS > 7 +	init_col(7); +#endif +	for (row = 0; row < AO_MATRIX_ROWS; row++) { +		ao_matrix_state[row] = _ao_matrix_read(row); +		ao_matrix_tick[row] = ao_time(); +	} +} diff --git a/src/drivers/ao_matrix.h b/src/drivers/ao_matrix.h new file mode 100644 index 00000000..ab5a1c51 --- /dev/null +++ b/src/drivers/ao_matrix.h @@ -0,0 +1,24 @@ +/* + * Copyright © 2017 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef _AO_MATRIX_H_ +#define _AO_MATRIX_H_ + +void +ao_matrix_poll(void); + +void +ao_matrix_init(void); + +#endif /* _AO_MATRIX_H_ */ diff --git a/src/drivers/ao_pad.c b/src/drivers/ao_pad.c index ffa833fe..16b4ae60 100644 --- a/src/drivers/ao_pad.c +++ b/src/drivers/ao_pad.c @@ -316,7 +316,7 @@ ao_pad(void)  			command.tick, command.box, ao_pad_box, command.cmd, command.channels);  		switch (command.cmd) { -		case AO_LAUNCH_ARM: +		case AO_PAD_ARM:  			if (command.box != ao_pad_box) {  				PRINTD ("box number mismatch\n");  				break; @@ -338,7 +338,7 @@ ao_pad(void)  			ao_pad_arm_time = ao_time();  			break; -		case AO_LAUNCH_QUERY: +		case AO_PAD_QUERY:  			if (command.box != ao_pad_box) {  				PRINTD ("box number mismatch\n");  				break; @@ -357,7 +357,7 @@ ao_pad(void)  				query.igniter_status[3]);  			ao_radio_cmac_send(&query, sizeof (query));  			break; -		case AO_LAUNCH_FIRE: +		case AO_PAD_FIRE:  			if (!ao_pad_armed) {  				PRINTD ("not armed\n");  				break; @@ -372,6 +372,29 @@ ao_pad(void)  			ao_pad_arm_time = ao_time();  			ao_wakeup(&ao_pad_ignite);  			break; +		case AO_PAD_STATIC: +			if (!ao_pad_armed) { +				PRINTD ("not armed\n"); +				break; +			} +#if HAS_LOG +			if (!ao_log_running) ao_log_start(); +#endif +			if ((uint16_t) (ao_time() - ao_pad_arm_time) > AO_SEC_TO_TICKS(20)) { +				PRINTD ("late pad arm_time %d time %d\n", +					ao_pad_arm_time, ao_time()); +				break; +			} +			PRINTD ("ignite\n"); +			ao_pad_ignite = ao_pad_armed; +			ao_pad_arm_time = ao_time(); +			ao_wakeup(&ao_pad_ignite); +			break; +		case AO_PAD_ENDSTATIC: +#if HAS_LOG +			ao_log_stop(); +#endif +			break;  		}  	}  } diff --git a/src/drivers/ao_pad.h b/src/drivers/ao_pad.h index 648d3005..e4115222 100644 --- a/src/drivers/ao_pad.h +++ b/src/drivers/ao_pad.h @@ -54,6 +54,11 @@ struct ao_pad_query {   */  #define AO_PAD_FIRE		3 +/* Fire current armed pads for 200ms, no report, logging test stand sensors + */ +#define AO_PAD_STATIC		4 +#define AO_PAD_ENDSTATIC	5 +  #define AO_PAD_FIRE_TIME	AO_MS_TO_TICKS(200)  #define AO_PAD_ARM_STATUS_DISARMED	0 diff --git a/src/drivers/ao_ps2.c b/src/drivers/ao_ps2.c new file mode 100644 index 00000000..29eecea8 --- /dev/null +++ b/src/drivers/ao_ps2.c @@ -0,0 +1,419 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include "ao.h" +#include "ao_ps2.h" +#include "ao_exti.h" + +static struct ao_fifo	ao_ps2_rx_fifo; + +static uint16_t		ao_ps2_tx; +static uint8_t		ao_ps2_tx_count; + +static AO_TICK_TYPE	ao_ps2_tick; +static uint16_t		ao_ps2_value; +static uint8_t		ao_ps2_count; + +uint8_t			ao_ps2_stdin; + +uint8_t			ao_ps2_scancode_set; + +#define AO_PS2_CLOCK_MODE(pull) ((pull) | AO_EXTI_MODE_FALLING | AO_EXTI_PRIORITY_MED) + +static void +ao_ps2_isr(void); + +static uint8_t +_ao_ps2_parity(uint8_t value) +{ +	uint8_t	parity = 1; +	uint8_t	b; + +	for (b = 0; b < 8; b++) { +		parity ^= (value & 1); +		value >>= 1; +	} +	return parity; +} + +static int +_ao_ps2_poll(void) +{ +	uint8_t	u; +	if (ao_fifo_empty(ao_ps2_rx_fifo)) { +		return AO_READ_AGAIN; +	} +	ao_fifo_remove(ao_ps2_rx_fifo, u); + +	return (int) u; +} + +uint8_t +ao_ps2_get(void) +{ +	int c; +	ao_arch_block_interrupts(); +	while ((c = _ao_ps2_poll()) == AO_READ_AGAIN) +		ao_sleep(&ao_ps2_rx_fifo); +	ao_arch_release_interrupts(); +	return (uint8_t) c; +} + + +int +ao_ps2_poll(void) +{ +	int	c; +	ao_arch_block_interrupts(); +	c = _ao_ps2_poll(); +	ao_arch_release_interrupts(); +	return (uint8_t) c; +} + +void +ao_ps2_put(uint8_t c) +{ +	ao_arch_block_interrupts(); +	ao_ps2_tx = ((uint16_t) c) | (_ao_ps2_parity(c) << 8) | (3 << 9); +	ao_ps2_tx_count = 11; +	ao_exti_disable(AO_PS2_CLOCK_PORT, AO_PS2_CLOCK_BIT); +	ao_arch_release_interrupts(); + +	/* pull the clock pin down */ +	ao_enable_output(AO_PS2_CLOCK_PORT, AO_PS2_CLOCK_BIT, AO_PS2_CLOCK_PIN, 0); +	ao_delay(0); + +	/* pull the data pin down for the start bit */ +	ao_enable_output(AO_PS2_DATA_PORT, AO_PS2_DATA_BIT, AO_PS2_DATA_PIN, 0); +	ao_delay(0); + +	/* switch back to input mode for the interrupt to work */ +	ao_exti_setup(AO_PS2_CLOCK_PORT, AO_PS2_CLOCK_BIT, +		      AO_PS2_CLOCK_MODE(AO_EXTI_MODE_PULL_UP), +		      ao_ps2_isr); +	ao_exti_enable(AO_PS2_CLOCK_PORT, AO_PS2_CLOCK_BIT); + +	/* wait for the bits to drain */ +	while (ao_ps2_tx_count) +		ao_sleep(&ao_ps2_tx_count); + +} + +static uint8_t	ao_ps2_down[128 / 8]; + +static void +ao_ps2_set_down(uint8_t code, uint8_t value) +{ +	uint8_t shift = (code & 0x07); +	uint8_t	byte = code >> 3; + +	ao_ps2_down[byte] = (ao_ps2_down[byte] & ~(1 << shift)) | (value << shift); +} + +uint8_t +ao_ps2_is_down(uint8_t code) +{ +	uint8_t shift = (code & 0x07); +	uint8_t	byte = code >> 3; + +	return (ao_ps2_down[byte] >> shift) & 1; +} + +static void +_ao_ps2_set_leds(void) +{ +	uint8_t	led = 0; +	if (ao_ps2_is_down(AO_PS2_CAPS_LOCK)) +		led |= AO_PS2_SET_LEDS_CAPS; +	if (ao_ps2_is_down(AO_PS2_NUM_LOCK)) +		led |= AO_PS2_SET_LEDS_NUM; +	if (ao_ps2_is_down(AO_PS2_SCROLL_LOCK)) +		led |= AO_PS2_SET_LEDS_SCROLL; +	ao_arch_release_interrupts(); +	ao_ps2_put(AO_PS2_SET_LEDS); +	while (ao_ps2_get() != 0xfa); +	ao_ps2_put(led); +	ao_arch_block_interrupts(); +} + +static uint8_t +ao_ps2_is_lock(uint8_t code) { +	switch (code) { +	case AO_PS2_CAPS_LOCK: +	case AO_PS2_NUM_LOCK: +	case AO_PS2_SCROLL_LOCK: +		return 1; +	} +	return 0; +} + +static void +_ao_ps2_set_scancode_set(uint8_t set) +{ +	ao_ps2_scancode_set = set; +	ao_arch_release_interrupts(); +	ao_ps2_put(AO_PS2_SET_SCAN_CODE_SET); +	while (ao_ps2_get() != 0xfa); +	ao_ps2_put(set); +	ao_ps2_put(AO_PS2_SET_KEY_TYPEMATIC_MAKE_BREAK); +	while (ao_ps2_get() != 0xfa); +	ao_arch_block_interrupts(); +} + +static int +_ao_ps2_poll_key(void) +{ +	int	c; +	uint8_t	set_led = 0; +	static uint8_t	saw_break; + +	c = _ao_ps2_poll(); +	if (c < 0) { +		if (ao_ps2_scancode_set != 3) { +			_ao_ps2_set_scancode_set(3); +		} +		return c; +	} + +	if (c == AO_PS2_BREAK) { +		saw_break = 1; +		return AO_READ_AGAIN; +	} +	if (c & 0x80) +		return AO_READ_AGAIN; + +	if (ao_ps2_is_lock(c)) { +		if (saw_break) { +			saw_break = 0; +			return AO_READ_AGAIN; +		} +		if (ao_ps2_is_down(c)) +			saw_break = 1; +		set_led = 1; +	} +	if (saw_break) { +		saw_break = 0; +		ao_ps2_set_down(c, 0); +		c |= 0x80; +	} else +		ao_ps2_set_down(c, 1); +	if (set_led) +		_ao_ps2_set_leds(); + +	if (ao_ps2_scancode_set != 3) +		_ao_ps2_set_scancode_set(3); + +	return c; +} + +int +ao_ps2_poll_key(void) +{ +	int	c; +	ao_arch_block_interrupts(); +	c = _ao_ps2_poll_key(); +	ao_arch_release_interrupts(); +	return c; +} + +uint8_t +ao_ps2_get_key(void) +{ +	int	c; +	ao_arch_block_interrupts(); +	while ((c = _ao_ps2_poll_key()) == AO_READ_AGAIN) +		ao_sleep(&ao_ps2_rx_fifo); +	ao_arch_release_interrupts(); +	return (uint8_t) c; +} + +static const uint8_t	ao_ps2_asciimap[128][2] = { +	[AO_PS2_A] = { 'a', 'A' }, +	[AO_PS2_B] = { 'b', 'B' }, +	[AO_PS2_C] = { 'c', 'C' }, +	[AO_PS2_D] = { 'd', 'D' }, +	[AO_PS2_E] = { 'e', 'E' }, +	[AO_PS2_F] = { 'f', 'F' }, +	[AO_PS2_G] = { 'g', 'G' }, +	[AO_PS2_H] = { 'h', 'H' }, +	[AO_PS2_I] = { 'i', 'I' }, +	[AO_PS2_J] = { 'j', 'J' }, +	[AO_PS2_K] = { 'k', 'K' }, +	[AO_PS2_L] = { 'l', 'L' }, +	[AO_PS2_M] = { 'm', 'M' }, +	[AO_PS2_N] = { 'n', 'N' }, +	[AO_PS2_O] = { 'o', 'O' }, +	[AO_PS2_P] = { 'p', 'P' }, +	[AO_PS2_Q] = { 'q', 'Q' }, +	[AO_PS2_R] = { 'r', 'R' }, +	[AO_PS2_S] = { 's', 'S' }, +	[AO_PS2_T] = { 't', 'T' }, +	[AO_PS2_U] = { 'u', 'U' }, +	[AO_PS2_V] = { 'v', 'V' }, +	[AO_PS2_W] = { 'w', 'W' }, +	[AO_PS2_X] = { 'x', 'X' }, +	[AO_PS2_Y] = { 'y', 'Y' }, +	[AO_PS2_Z] = { 'z', 'Z' }, + +	[AO_PS2_0] = { '0', ')' }, +	[AO_PS2_1] = { '1', '!' }, +	[AO_PS2_2] = { '2', '@' }, +	[AO_PS2_3] = { '3', '#' }, +	[AO_PS2_4] = { '4', '$' }, +	[AO_PS2_5] = { '5', '%' }, +	[AO_PS2_6] = { '6', '^' }, +	[AO_PS2_7] = { '7', '&' }, +	[AO_PS2_8] = { '8', '*' }, +	[AO_PS2_9] = { '9', '(' }, + +	[AO_PS2_GRAVE] = { '`', '~' }, +	[AO_PS2_HYPHEN] = { '-', '_' }, +	[AO_PS2_EQUAL] = { '=', '+' }, +	[AO_PS2_BACKSLASH] = { '\\', '|' }, +	[AO_PS2_BACKSPACE] = { '\010', '\010' }, +	[AO_PS2_SPACE] = { ' ', ' ' }, +	[AO_PS2_TAB] = { '\t', '\t' }, + +	[AO_PS2_ENTER] = { '\r', '\r' }, +	[AO_PS2_ESC] = { '\033', '\033' }, + +	[AO_PS2_OPEN_SQ] = { '[', '{' }, +	[AO_PS2_DELETE] = { '\177', '\177' }, + +	[AO_PS2_KP_TIMES] = { '*', '*' }, +	[AO_PS2_KP_PLUS] = { '+', '+' }, +	[AO_PS2_KP_ENTER] = { '\r', '\r' }, +	[AO_PS2_KP_DECIMAL] = { '.', '.' }, +	[AO_PS2_KP_0] = { '0', '0' }, +	[AO_PS2_KP_1] = { '1', '1' }, +	[AO_PS2_KP_2] = { '2', '2' }, +	[AO_PS2_KP_3] = { '3', '3' }, +	[AO_PS2_KP_4] = { '4', '4' }, +	[AO_PS2_KP_5] = { '5', '5' }, +	[AO_PS2_KP_6] = { '6', '6' }, +	[AO_PS2_KP_7] = { '7', '7' }, +	[AO_PS2_KP_8] = { '8', '8' }, +	[AO_PS2_KP_9] = { '9', '9' }, +	[AO_PS2_CLOSE_SQ] = { ']', '}' }, +	[AO_PS2_SEMICOLON] = { ';', ':' }, +	[AO_PS2_ACUTE] = { '\'', '"' }, +	[AO_PS2_COMMA] = { ',', '<' }, +	[AO_PS2_PERIOD] = { '.', '>' }, +	[AO_PS2_SLASH] = { '/', '?' }, +}; + +int +ao_ps2_ascii(uint8_t key) +{ +	uint8_t	col; +	char a; + +	/* Skip key releases */ +	if (key & 0x80) +		return AO_READ_AGAIN; + +	col = 0; +	if (ao_ps2_is_down(AO_PS2_L_SHIFT) || ao_ps2_is_down(AO_PS2_R_SHIFT)) +		col = 1; + +	/* caps lock */ +	a = ao_ps2_asciimap[key][0]; +	if (!a) +		return AO_READ_AGAIN; + +	if ('a' <= a && a <= 'z') +		if (ao_ps2_is_down(AO_PS2_CAPS_LOCK)) +			col ^= 1; +	a = ao_ps2_asciimap[key][col]; +	if ('@' <= a && a <= 0x7f && (ao_ps2_is_down(AO_PS2_L_CTRL) || ao_ps2_is_down(AO_PS2_R_CTRL))) +		a &= 0x1f; +	return a; +} + +int +_ao_ps2_pollchar(void) +{ +	int	key; + +	key = _ao_ps2_poll_key(); +	if (key < 0) +		return key; +	return ao_ps2_ascii(key); +} + +char +ao_ps2_getchar(void) +{ +	int	c; +	ao_arch_block_interrupts(); +	while ((c = _ao_ps2_pollchar()) == AO_READ_AGAIN) +		ao_sleep(&ao_ps2_rx_fifo); +	ao_arch_release_interrupts(); +	return (char) c; +} + +static void +ao_ps2_isr(void) +{ +	uint8_t	bit; + +	if (ao_ps2_tx_count) { +		ao_gpio_set(AO_PS2_DATA_PORT, AO_PS2_DATA_BIT, AO_PS2_DATA_PIN, ao_ps2_tx&1); +		ao_ps2_tx >>= 1; +		ao_ps2_tx_count--; +		if (!ao_ps2_tx_count) { +			ao_enable_input(AO_PS2_DATA_PORT, AO_PS2_DATA_BIT, AO_EXTI_MODE_PULL_UP); +			ao_wakeup(&ao_ps2_tx_count); +		} +		return; +	} +	/* reset if its been a while */ +	if ((ao_tick_count - ao_ps2_tick) > AO_MS_TO_TICKS(100)) +		ao_ps2_count = 0; +	ao_ps2_tick = ao_tick_count; + +	bit = ao_gpio_get(AO_PS2_DATA_PORT, AO_PS2_DATA_BIT, AO_PS2_DATA_PIN); +	if (ao_ps2_count == 0) { +		/* check for start bit, ignore if not zero */ +		if (bit) +			return; +		ao_ps2_value = 0; +	} else if (ao_ps2_count < 9) { +		ao_ps2_value |= (bit << (ao_ps2_count - 1)); +	} else if (ao_ps2_count == 10) { +		ao_fifo_insert(ao_ps2_rx_fifo, ao_ps2_value); +		ao_wakeup(&ao_ps2_rx_fifo); +		if (ao_ps2_stdin) +			ao_wakeup(&ao_stdin_ready); +		ao_ps2_count = 0; +		return; +	} +	ao_ps2_count++; +} + +void +ao_ps2_init(void) +{ +	ao_enable_input(AO_PS2_DATA_PORT, AO_PS2_DATA_BIT, +			AO_EXTI_MODE_PULL_UP); + +	ao_enable_port(AO_PS2_CLOCK_PORT); + +	ao_exti_setup(AO_PS2_CLOCK_PORT, AO_PS2_CLOCK_BIT, +		      AO_PS2_CLOCK_MODE(AO_EXTI_MODE_PULL_UP), +		      ao_ps2_isr); +	ao_exti_enable(AO_PS2_CLOCK_PORT, AO_PS2_CLOCK_BIT); + +	ao_ps2_scancode_set = 2; +} diff --git a/src/drivers/ao_ps2.h b/src/drivers/ao_ps2.h new file mode 100644 index 00000000..f1f05ee5 --- /dev/null +++ b/src/drivers/ao_ps2.h @@ -0,0 +1,220 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef _AO_PS2_H_ +#define _AO_PS2_H_ + +extern uint8_t			ao_ps2_stdin; + +int +ao_ps2_poll(void); + +uint8_t +ao_ps2_get(void); + +void +ao_ps2_put(uint8_t b); + +uint8_t +ao_ps2_is_down(uint8_t code); + +int +ao_ps2_poll_key(void); + +uint8_t +ao_ps2_get_key(void); + +int +ao_ps2_ascii(uint8_t key); + +int +_ao_ps2_pollchar(void); + +char +ao_ps2_getchar(void); + +void +ao_ps2_init(void); + +/* From http://computer-engineering.org/ps2keyboard/ */ + +/* Device responds with ACK and then resets */ +#define AO_PS2_RESET				0xff + +/* Device retransmits last byte */ +#define AO_PS2_RESEND				0xfe + +/* Setting key report only works in mode 3 */ + +/* Disable break and typematic for specified mode 3 keys. Terminate with invalid key */ +#define AO_PS2_SET_KEY_MAKE			0xfd + +/* Disable typematic for keys */ +#define AO_PS2_SET_KEY_MAKE_BREAK		0xfc + +/* Disable break code for keys */ +#define AO_PS2_SET_KEY_TYPEMATIC		0xfb + +/* Enable make, break and typematic */ +#define AO_PS2_SET_KEY_TYPEMATIC_MAKE_BREAK	0xfa + +/* Disable break and typematic for all */ +#define AO_PS2_SET_ALL_MAKE			0xf9 + +/* Disable typematic for all */ +#define AO_PS2_SET_ALL_MAKE_BREAK		0xf8 + +/* Disable break for all */ +#define AO_PS2_SET_ALL_TYPEMATIC		0xf7 + +/* Set keyboard to default (repeat, report and scan code set 2) */ +#define AO_PS2_SET_DEFAULT			0xf6 + +/* Disable and reset to default */ +#define AO_PS2_DISABLE				0xf5 + +/* Enable */ +#define AO_PS2_ENABLE				0xf4 + +/* Set repeat rate. Bytes 5-6 are the start delay, bits 0-4 are the rate */ +#define AO_PS2_SET_REPEAT_RATE			0xf3 + +/* Read keyboard id. Returns two bytes */ +#define AO_PS2_GETID				0xf2 + +/* Set scan code (1, 2, or 3) */ +#define AO_PS2_SET_SCAN_CODE_SET		0xf0 + +/* Echo. Keyboard replies with Echo */ +#define AO_PS2_ECHO				0xee + +/* Set LEDs */ +#define AO_PS2_SET_LEDS				0xed +# define AO_PS2_SET_LEDS_SCROLL			0x01 +# define AO_PS2_SET_LEDS_NUM			0x02 +# define AO_PS2_SET_LEDS_CAPS			0x04 + +#define AO_PS2_BREAK				0xf0 +#define AO_PS2_ACK				0xfa +#define AO_PS2_ERROR				0xfc +#define AO_PS2_NAK				0xfe + +/* Scan code set 3 */ + +#define AO_PS2_A		0x1c +#define AO_PS2_B		0x32 +#define AO_PS2_C		0x21 +#define AO_PS2_D		0x23 +#define AO_PS2_E		0x24 +#define AO_PS2_F		0x2b +#define AO_PS2_G		0x34 +#define AO_PS2_H		0x33 +#define AO_PS2_I		0x43 +#define AO_PS2_J		0x3b +#define AO_PS2_K		0x42 +#define AO_PS2_L		0x4b +#define AO_PS2_M		0x3a +#define AO_PS2_N		0x31 +#define AO_PS2_O		0x44 +#define AO_PS2_P		0x4d +#define AO_PS2_Q		0x15 +#define AO_PS2_R		0x2d +#define AO_PS2_S		0x1b +#define AO_PS2_T		0x2c +#define AO_PS2_U		0x3c +#define AO_PS2_V		0x2a +#define AO_PS2_W		0x1d +#define AO_PS2_X		0x22 +#define AO_PS2_Y		0x35 +#define AO_PS2_Z		0x1a +#define AO_PS2_0		0x45 +#define AO_PS2_1		0x16 +#define AO_PS2_2		0x1e +#define AO_PS2_3		0x26 +#define AO_PS2_4		0x25 +#define AO_PS2_5		0x2e +#define AO_PS2_6		0x36 +#define AO_PS2_7		0x3d +#define AO_PS2_8		0x3e +#define AO_PS2_9		0x46 +#define AO_PS2_GRAVE		0x0e +#define AO_PS2_HYPHEN		0x4e +#define AO_PS2_EQUAL		0x55 +#define AO_PS2_BACKSLASH	0x5c +#define AO_PS2_BACKSPACE	0x66 +#define AO_PS2_SPACE		0x29 +#define AO_PS2_TAB		0x0d +#define AO_PS2_CAPS_LOCK	0x14 +#define AO_PS2_L_SHIFT		0x12 +#define AO_PS2_L_CTRL		0x11 +#define AO_PS2_L_WIN		0x8b +#define AO_PS2_L_ALT		0x19 +#define AO_PS2_R_SHIFT		0x59 +#define AO_PS2_R_CTRL		0x58 +#define AO_PS2_R_WIN		0x8c +#define AO_PS2_R_ALT		0x39 +#define AO_PS2_APPS		0x8d +#define AO_PS2_ENTER		0x5a +#define AO_PS2_ESC		0x08 +#define AO_PS2_F1		0x07 +#define AO_PS2_F2		0x0f +#define AO_PS2_F3		0x17 +#define AO_PS2_F4		0x1f +#define AO_PS2_F5		0x27 +#define AO_PS2_F6		0x2f +#define AO_PS2_F7		0x37 +#define AO_PS2_F8		0x3f +#define AO_PS2_F9		0x47 +#define AO_PS2_F10		0x4f +#define AO_PS2_F11		0x56 +#define AO_PS2_F12		0x5e +#define AO_PS2_PRNT_SCRN	0x57 +#define AO_PS2_SCROLL_LOCK	0x5f +#define AO_PS2_PAUSE		0x62 +#define AO_PS2_OPEN_SQ		0x54 +#define AO_PS2_INSERT		0x67 +#define AO_PS2_HOME		0x6e +#define AO_PS2_PG_UP		0x6f +#define AO_PS2_DELETE		0x64 +#define AO_PS2_END		0x65 +#define AO_PS2_PG_DN		0x6d +#define AO_PS2_UP		0x63 +#define AO_PS2_LEFT		0x61 +#define AO_PS2_DOWN		0x60 +#define AO_PS2_RIGHT		0x6a +#define AO_PS2_NUM_LOCK		0x76 +#define AO_PS2_KP_TIMES		0x7e +#define AO_PS2_KP_PLUS		0x7c +#define AO_PS2_KP_ENTER		0x79 +#define AO_PS2_KP_DECIMAL	0x71 +#define AO_PS2_KP_0		0x70 +#define AO_PS2_KP_1		0x69 +#define AO_PS2_KP_2		0x72 +#define AO_PS2_KP_3		0x7a +#define AO_PS2_KP_4		0x6b +#define AO_PS2_KP_5		0x73 +#define AO_PS2_KP_6		0x74 +#define AO_PS2_KP_7		0x6c +#define AO_PS2_KP_8		0x75 +#define AO_PS2_KP_9		0x7d +#define AO_PS2_CLOSE_SQ		0x5b +#define AO_PS2_SEMICOLON	0x4c +#define AO_PS2_ACUTE		0x52 +#define AO_PS2_COMMA		0x41 +#define AO_PS2_PERIOD		0x49 +#define AO_PS2_SLASH		0x4a + +#define AO_PS2_RELEASE_FLAG	0x80 + +#endif /* _AO_PS2_H_ */ diff --git a/src/drivers/ao_sdcard.c b/src/drivers/ao_sdcard.c index 4b17c5e3..45454000 100644 --- a/src/drivers/ao_sdcard.c +++ b/src/drivers/ao_sdcard.c @@ -38,13 +38,19 @@ extern uint8_t ao_radio_mutex;  #define ao_sdcard_deselect()		ao_gpio_set(AO_SDCARD_SPI_CS_PORT,AO_SDCARD_SPI_CS_PIN,AO_SDCARD_SPI_CS,1)  /* Include SD card commands */ +#ifndef SDCARD_DEBUG  #define SDCARD_DEBUG	0 +#endif  /* Spew SD tracing */ +#ifndef SDCARD_TRACE  #define SDCARD_TRACE	0 +#endif  /* Emit error and warning messages */ +#ifndef SDCARD_WARN  #define SDCARD_WARN	0 +#endif  static uint8_t	initialized;  static uint8_t	present; diff --git a/src/drivers/ao_vga.c b/src/drivers/ao_vga.c new file mode 100644 index 00000000..909e3109 --- /dev/null +++ b/src/drivers/ao_vga.c @@ -0,0 +1,366 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include "ao.h" +#include "ao_vga.h" + +/* VGA output from the SPI port + * + * Connections: + * + *			STM	VGA + *	GND			4,6,7,8,9,10 + *	HSYNC		PA5	13 + *	VSYNC		PB5	14 + *	RGB		PB4	1,2,3 + * + *	pixel clock	PA8 -> PB3 + *	pixel enable	PA1 -> PA15 + */ + +/* GRF formula for 640x480 yields a pixel clock very close to 24MHz. Pad by + * three scanlines to hit exactly that value + */ + +#define HACTIVE 	(640) +#define HSYNC_START 	(656) +#define HSYNC_END	(720) +#define HTOTAL		(800) + +#define	VACTIVE		480 +#define VSYNC_START	481 +#define VSYNC_END	484 +#define VTOTAL		500 + +/* + * The horizontal counter is set so that the end of hsync is reached + * at the maximum counter value. That means that the hblank interval + * is offset by HSYNC_END. + */ + +#define HSYNC		(HSYNC_END - HSYNC_START) +#define HBLANK_END	(HTOTAL - HSYNC_END) +#define HBLANK_START	(HBLANK_END + HACTIVE) + +/* + * The vertical counter is set so that the end of vsync is reached at + * the maximum counter value.  That means that the vblank interval is + * offset by VSYNC_END. We send a blank line at the start of the + * frame, so each of these is off by one + */ +#define VSYNC		(VSYNC_END - VSYNC_START) +#define VBLANK_END	(VTOTAL - VSYNC_END) +#define VBLANK_START	(VBLANK_END + VACTIVE) + +#define WIDTH_BYTES	(AO_VGA_WIDTH >> 3) +#define SCANOUT		((WIDTH_BYTES+2) >> 1) + +uint32_t	ao_vga_fb[AO_VGA_STRIDE * AO_VGA_HEIGHT]; + +const struct ao_bitmap ao_vga_bitmap = { +	.base = ao_vga_fb, +	.stride = AO_VGA_STRIDE, +	.width = AO_VGA_WIDTH, +	.height = AO_VGA_HEIGHT +}; + +static uint32_t	*scanline; + +#define DMA_INDEX	STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_TX) + +#define DMA_CCR(en)	((0 << STM_DMA_CCR_MEM2MEM) |			\ +			 (STM_DMA_CCR_PL_VERY_HIGH << STM_DMA_CCR_PL) | \ +			 (STM_DMA_CCR_MSIZE_16 << STM_DMA_CCR_MSIZE) |	\ +			 (STM_DMA_CCR_PSIZE_16 << STM_DMA_CCR_PSIZE) |	\ +			 (1 << STM_DMA_CCR_MINC) |			\ +			 (0 << STM_DMA_CCR_PINC) |			\ +			 (0 << STM_DMA_CCR_CIRC) |			\ +			 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) | \ +			 (0 << STM_DMA_CCR_TCIE) |			\ +			 (en << STM_DMA_CCR_EN)) + + +void stm_tim2_isr(void) +{ +	int16_t	line = stm_tim3.cnt; + +	if (VBLANK_END <= line && line < VBLANK_START) { +		/* Disable */ +		stm_dma.channel[DMA_INDEX].ccr = DMA_CCR(0); +		/* Reset DMA engine for the next scanline */ +		stm_dma.channel[DMA_INDEX].cmar = scanline; +		stm_dma.channel[DMA_INDEX].cndtr = SCANOUT; + +		/* reset SPI */ +		(void) stm_spi1.dr; +		(void) stm_spi1.sr; + +		/* Enable */ +		stm_dma.channel[DMA_INDEX].ccr = DMA_CCR(1); +		if (((line - VBLANK_END) & 1)) +			scanline += AO_VGA_STRIDE; +	} else { +		scanline = ao_vga_fb; +	} +	stm_tim2.sr = 0; +} + + +void +ao_vga_init(void) +{ +	uint32_t	cfgr; + +	/* Initialize spi1 using MISO PB4 for output */ +	stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN); +	stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN); + +	stm_ospeedr_set(&stm_gpiob, 4, STM_OSPEEDR_40MHz); +	stm_afr_set(&stm_gpiob, 4, STM_AFR_AF5); +	stm_afr_set(&stm_gpiob, 3, STM_AFR_AF5); +	stm_afr_set(&stm_gpioa, 15, STM_AFR_AF5); + +	/* turn on SPI */ +	stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN); + +	stm_spi1.cr1 = ((1 << STM_SPI_CR1_BIDIMODE) |		/* Two wire mode */ +			(1 << STM_SPI_CR1_BIDIOE) | +			(0 << STM_SPI_CR1_CRCEN) |		/* CRC disabled */ +			(0 << STM_SPI_CR1_CRCNEXT) | +			(1 << STM_SPI_CR1_DFF) | +			(0 << STM_SPI_CR1_RXONLY) |		/* transmit, not receive */ +			(0 << STM_SPI_CR1_SSM) |        	/* Software SS handling */ +			(1 << STM_SPI_CR1_SSI) |		/*  ... */ +			(1 << STM_SPI_CR1_LSBFIRST) |		/* Little endian */ +			(1 << STM_SPI_CR1_SPE) |		/* Enable SPI unit */ +			(0 << STM_SPI_CR1_BR) |			/* baud rate to pclk/2 */ +			(0 << STM_SPI_CR1_MSTR) |		/* slave */ +			(0 << STM_SPI_CR1_CPOL) |		/* Format 0 */ +			(0 << STM_SPI_CR1_CPHA)); +	stm_spi1.cr2 = ((0 << STM_SPI_CR2_TXEIE) | +			(0 << STM_SPI_CR2_RXNEIE) | +			(0 << STM_SPI_CR2_ERRIE) | +			(0 << STM_SPI_CR2_SSOE) | +			(1 << STM_SPI_CR2_TXDMAEN) | +			(0 << STM_SPI_CR2_RXDMAEN)); + +	(void) stm_spi1.dr; +	(void) stm_spi1.sr; + +	/* Grab the DMA channel for SPI1 MOSI */ +	stm_dma.channel[DMA_INDEX].cpar = &stm_spi1.dr; +	stm_dma.channel[DMA_INDEX].cmar = ao_vga_fb; + +	/* +	 * Hsync Configuration +	 */ +	/* Turn on timer 2 */ +	stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_TIM2EN); + +	/* tim2 runs at full speed */ +	stm_tim2.psc = 0; + +	/* Disable channels while modifying */ +	stm_tim2.ccer = 0; + +	/* Channel 1 hsync PWM values */ +	stm_tim2.ccr1 = HSYNC; + +	/* Channel 2 trigger scanout */ +	/* wait for the time to start scanout */ +	stm_tim2.ccr2 = HBLANK_END; + +	stm_tim2.ccr3 = 32; + +	/* Configure channel 1 to output on the pin and +	 * channel 2 to to set the trigger for the vsync timer +	 */ +	stm_tim2.ccmr1 = ((0 << STM_TIM234_CCMR1_OC2CE) | +			  (STM_TIM234_CCMR1_OC2M_PWM_MODE_1 << STM_TIM234_CCMR1_OC2M)  | +			  (1 << STM_TIM234_CCMR1_OC2PE) | +			  (0 << STM_TIM234_CCMR1_OC2FE) | +			  (STM_TIM234_CCMR1_CC2S_OUTPUT << STM_TIM234_CCMR1_CC2S) | + +			  (0 << STM_TIM234_CCMR1_OC1CE) | +			  (STM_TIM234_CCMR1_OC1M_PWM_MODE_1 << STM_TIM234_CCMR1_OC1M)  | +			  (1 << STM_TIM234_CCMR1_OC1PE) | +			  (0 << STM_TIM234_CCMR1_OC1FE) | +			  (STM_TIM234_CCMR1_CC1S_OUTPUT << STM_TIM234_CCMR1_CC1S)); + +	stm_tim2.ccmr2 = ((0 << STM_TIM234_CCMR2_OC4CE) | +			  (0 << STM_TIM234_CCMR2_OC4M)  | +			  (0 << STM_TIM234_CCMR2_OC4PE) | +			  (0 << STM_TIM234_CCMR2_OC4FE) | +			  (0 << STM_TIM234_CCMR2_CC4S) | + +			  (0 << STM_TIM234_CCMR2_OC3CE) | +			  (STM_TIM234_CCMR2_OC3M_PWM_MODE_1 << STM_TIM234_CCMR2_OC3M)  | +			  (1 << STM_TIM234_CCMR2_OC3PE) | +			  (0 << STM_TIM234_CCMR2_OC3FE) | +			  (0 << STM_TIM234_CCMR2_CC3S)); + +	/* One scanline */ +	stm_tim2.arr = HTOTAL; + +	stm_tim2.cnt = 0; + +	/* Update the register contents */ +	stm_tim2.egr |= (1 << STM_TIM234_EGR_UG); + +	/* Enable the timer */ + +	/* Enable the output */ +	stm_tim2.ccer = ((0 << STM_TIM234_CCER_CC2NP) | +			 (STM_TIM234_CCER_CC2P_ACTIVE_HIGH << STM_TIM234_CCER_CC2P) | +			 (1 << STM_TIM234_CCER_CC2E) | +			 (0 << STM_TIM234_CCER_CC1NP) | +			 (STM_TIM234_CCER_CC1P_ACTIVE_LOW << STM_TIM234_CCER_CC1P) | +			 (1 << STM_TIM234_CCER_CC1E)); + +	stm_tim2.cr2 = ((0 << STM_TIM234_CR2_TI1S) | +			(STM_TIM234_CR2_MMS_UPDATE << STM_TIM234_CR2_MMS) | +			(0 << STM_TIM234_CR2_CCDS)); + +	/* hsync is not a slave timer */ +	stm_tim2.smcr = 0; + +	/* Send an interrupt on channel 3 */ +	stm_tim2.dier = ((1 << STM_TIM234_DIER_CC3IE)); + +	stm_tim2.cr1 = ((STM_TIM234_CR1_CKD_1 << STM_TIM234_CR1_CKD) | +			(1 << STM_TIM234_CR1_ARPE) | +			(STM_TIM234_CR1_CMS_EDGE << STM_TIM234_CR1_CMS) | +			(STM_TIM234_CR1_DIR_UP << STM_TIM234_CR1_DIR) | +			(0 << STM_TIM234_CR1_OPM) | +			(1 << STM_TIM234_CR1_URS) | +			(0 << STM_TIM234_CR1_UDIS) | +			(0 << STM_TIM234_CR1_CEN)); + +	/* Hsync is on PA5 which is Timer 2 CH1 output */ +	stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN); +	stm_ospeedr_set(&stm_gpioa, 5, STM_OSPEEDR_40MHz); +	stm_afr_set(&stm_gpioa, 5, STM_AFR_AF1); + +	/* pixel transmit enable is on PA1 */ +	stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN); +	stm_ospeedr_set(&stm_gpioa, 1, STM_OSPEEDR_40MHz); +	stm_afr_set(&stm_gpioa, 1, STM_AFR_AF1); + +	/* +	 * Vsync configuration +	 */ + +	/* Turn on timer 3, slaved to timer 1 using ITR1 (table 61) */ +	stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_TIM3EN); + +	/* No prescale */ +	stm_tim3.psc = 0; + +	/* Channel 1 or 2 vsync PWM values */ +	stm_tim3.ccr1 = VSYNC; +	stm_tim3.ccr2 = VSYNC; + +	stm_tim3.ccmr1 = ((0 << STM_TIM234_CCMR1_OC2CE) | +			  (STM_TIM234_CCMR1_OC2M_PWM_MODE_1 << STM_TIM234_CCMR1_OC2M)  | +			  (1 << STM_TIM234_CCMR1_OC2PE) | +			  (0 << STM_TIM234_CCMR1_OC2FE) | +			  (STM_TIM234_CCMR1_CC2S_OUTPUT << STM_TIM234_CCMR1_CC2S) | + +			  (0 << STM_TIM234_CCMR1_OC1CE) | +			  (STM_TIM234_CCMR1_OC1M_PWM_MODE_1 << STM_TIM234_CCMR1_OC1M)  | +			  (1 << STM_TIM234_CCMR1_OC1PE) | +			  (0 << STM_TIM234_CCMR1_OC1FE) | +			  (STM_TIM234_CCMR1_CC1S_OUTPUT << STM_TIM234_CCMR1_CC1S)); + +	stm_tim3.arr = VTOTAL; +	stm_tim3.cnt = 0; + +	/* Update the register contents */ +	stm_tim3.egr |= (1 << STM_TIM234_EGR_UG); + +	/* Enable the timer */ + +	/* Enable the output */ +	stm_tim3.ccer = ((0 << STM_TIM234_CCER_CC1NP) | +			 (STM_TIM234_CCER_CC2P_ACTIVE_LOW << STM_TIM234_CCER_CC2P) | +			 (1 << STM_TIM234_CCER_CC2E) | +			 (STM_TIM234_CCER_CC1P_ACTIVE_LOW << STM_TIM234_CCER_CC1P) | +			 (1 << STM_TIM234_CCER_CC1E)); + +	stm_tim3.cr2 = ((0 << STM_TIM234_CR2_TI1S) | +			(STM_TIM234_CR2_MMS_UPDATE << STM_TIM234_CR2_MMS) | +			(0 << STM_TIM234_CR2_CCDS)); + +	stm_tim3.smcr = 0; +	stm_tim3.smcr = ((0 << STM_TIM234_SMCR_ETP) | +			 (0 << STM_TIM234_SMCR_ECE) | +			 (STM_TIM234_SMCR_ETPS_OFF << STM_TIM234_SMCR_ETPS) | +			 (STM_TIM234_SMCR_ETF_NONE << STM_TIM234_SMCR_ETF) | +			 (0 << STM_TIM234_SMCR_MSM) | +			 (STM_TIM234_SMCR_TS_ITR1 << STM_TIM234_SMCR_TS) | +			 (0 << STM_TIM234_SMCR_OCCS) | +			 (STM_TIM234_SMCR_SMS_EXTERNAL_CLOCK << STM_TIM234_SMCR_SMS)); + +	stm_tim3.dier = 0; + +	stm_tim3.cr1 = ((STM_TIM234_CR1_CKD_1 << STM_TIM234_CR1_CKD) | +			(1 << STM_TIM234_CR1_ARPE) | +			(STM_TIM234_CR1_CMS_EDGE << STM_TIM234_CR1_CMS) | +			(STM_TIM234_CR1_DIR_UP << STM_TIM234_CR1_DIR) | +			(0 << STM_TIM234_CR1_OPM) | +			(1 << STM_TIM234_CR1_URS) | +			(0 << STM_TIM234_CR1_UDIS) | +			(1 << STM_TIM234_CR1_CEN)); + +	/* Vsync is on PB5 which is is Timer 3 CH2 output */ +	stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN); +	stm_ospeedr_set(&stm_gpiob, 5, STM_OSPEEDR_40MHz); +	stm_afr_set(&stm_gpiob, 5, STM_AFR_AF2); + +	/* Use MCO for the pixel clock, that appears on PA8 */ +	cfgr = stm_rcc.cfgr & ~((STM_RCC_CFGR_MCOPRE_MASK << STM_RCC_CFGR_MCOPRE) | +				(STM_RCC_CFGR_MCOSEL_MASK << STM_RCC_CFGR_MCOSEL)); + +	cfgr |= ((STM_RCC_CFGR_MCOPRE_DIV_2 << STM_RCC_CFGR_MCOPRE) | +		 (STM_RCC_CFGR_MCOSEL_SYSCLK << STM_RCC_CFGR_MCOSEL)); + +	stm_rcc.cfgr = cfgr; + +	stm_ospeedr_set(&stm_gpioa, 8, STM_OSPEEDR_40MHz); +	stm_afr_set(&stm_gpioa, 8, STM_AFR_AF0); + +	/* Enable the scanline interrupt */ +	stm_nvic_set_priority(STM_ISR_TIM2_POS, AO_STM_NVIC_NONMASK_PRIORITY); +	stm_nvic_set_enable(STM_ISR_TIM2_POS); +} + +uint8_t	enabled; + +void +ao_vga_enable(int enable) +{ +	if (enable) { +		if (!enabled) { +			++ao_task_minimize_latency; +			enabled = 1; +		} +		stm_tim2.cr1 |= (1 << STM_TIM234_CR1_CEN); +	} else { +		if (enabled) { +			--ao_task_minimize_latency; +			enabled = 0; +		} +		stm_tim2.cr1 &= ~(1 << STM_TIM234_CR1_CEN); +	} +} diff --git a/src/drivers/ao_vga.h b/src/drivers/ao_vga.h new file mode 100644 index 00000000..7d9d6b39 --- /dev/null +++ b/src/drivers/ao_vga.h @@ -0,0 +1,39 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef _AO_VGA_H_ +#define _AO_VGA_H_ + +#include "ao_draw.h" + +void +ao_vga_init(void); + +void +ao_vga_enable(int active); + +/* Active frame buffer */ +#define AO_VGA_WIDTH		320 +#define AO_VGA_HEIGHT		240 + +/* Pad on the right so that there are zeros on the output after the line */ +#define AO_VGA_HPAD		32 + +#define AO_VGA_STRIDE		((AO_VGA_WIDTH + AO_VGA_HPAD) >> AO_SHIFT) + +extern uint32_t	ao_vga_fb[AO_VGA_STRIDE * AO_VGA_HEIGHT]; + +extern const struct ao_bitmap ao_vga_bitmap; + +#endif /* _AO_VGA_H_ */ diff --git a/src/kernel/ao.h b/src/kernel/ao.h index fb41d7a9..e56fbb2e 100644 --- a/src/kernel/ao.h +++ b/src/kernel/ao.h @@ -170,6 +170,9 @@ void  ao_put_string(__code char *s);  void +ao_cmd_readline(void); + +char  ao_cmd_lex(void);  void @@ -853,33 +856,6 @@ struct ao_fifo {  #include <ao_aes.h>  #endif -/* ao_launch.c */ - -struct ao_launch_command { -	uint16_t	tick; -	uint16_t	serial; -	uint8_t		cmd; -	uint8_t		channel; -	uint16_t	unused; -}; - -#define AO_LAUNCH_QUERY		1 - -struct ao_launch_query { -	uint16_t	tick; -	uint16_t	serial; -	uint8_t		channel; -	uint8_t		valid; -	uint8_t		arm_status; -	uint8_t		igniter_status; -}; - -#define AO_LAUNCH_ARM		2 -#define AO_LAUNCH_FIRE		3 - -void -ao_launch_init(void); -  /*   * ao_log_single.c   */ diff --git a/src/kernel/ao_cmd.c b/src/kernel/ao_cmd.c index 10716afd..881f3500 100644 --- a/src/kernel/ao_cmd.c +++ b/src/kernel/ao_cmd.c @@ -24,13 +24,15 @@ __pdata uint32_t ao_cmd_lex_u32;  __pdata char	ao_cmd_lex_c;  __pdata enum ao_cmd_status ao_cmd_status; +#ifndef AO_CMD_LEN  #if AO_PYRO_NUM -#define CMD_LEN 128 +#define AO_CMD_LEN 128  #else -#define CMD_LEN	48 +#define AO_CMD_LEN	48 +#endif  #endif -static __xdata char	cmd_line[CMD_LEN]; +static __xdata char	cmd_line[AO_CMD_LEN];  static __pdata uint8_t	cmd_len;  static __pdata uint8_t	cmd_i; @@ -48,8 +50,8 @@ backspace(void)  	ao_put_string ("\010 \010");  } -static void -readline(void) +void +ao_cmd_readline(void)  {  	char c;  	if (ao_echo()) @@ -88,7 +90,7 @@ readline(void)  			break;  		} -		if (cmd_len >= CMD_LEN - 2) +		if (cmd_len >= AO_CMD_LEN - 2)  			continue;  		cmd_line[cmd_len++] = c;  		if (ao_echo()) @@ -99,12 +101,13 @@ readline(void)  	cmd_i = 0;  } -void +char  ao_cmd_lex(void)  {  	ao_cmd_lex_c = '\n';  	if (cmd_i < cmd_len)  		ao_cmd_lex_c = cmd_line[cmd_i++]; +	return ao_cmd_lex_c;  }  static void @@ -307,7 +310,7 @@ version(void)  #endif  #endif  #if defined(AO_BOOT_APPLICATION_BASE) && defined(AO_BOOT_APPLICATION_BOUND) -	       , (uint32_t) AO_BOOT_APPLICATION_BOUND - (uint32_t) AO_BOOT_APPLICATION_BASE +	       , (unsigned) ((uint32_t) AO_BOOT_APPLICATION_BOUND - (uint32_t) AO_BOOT_APPLICATION_BASE)  #endif  		);  	printf("software-version %s\n", ao_version); @@ -376,7 +379,7 @@ ao_cmd(void)  	void (*__xdata func)(void);  	for (;;) { -		readline(); +		ao_cmd_readline();  		ao_cmd_lex();  		ao_cmd_white();  		c = ao_cmd_lex_c; diff --git a/src/kernel/ao_log.h b/src/kernel/ao_log.h index 13eb05bf..a2f2c6ca 100644 --- a/src/kernel/ao_log.h +++ b/src/kernel/ao_log.h @@ -47,10 +47,12 @@ extern __pdata enum ao_flight_state ao_log_state;  #define AO_LOG_FORMAT_TELEMEGA_OLD	5	/* 32 byte typed telemega records */  #define AO_LOG_FORMAT_EASYMINI		6	/* 16-byte MS5607 baro only, 3.0V supply */  #define AO_LOG_FORMAT_TELEMETRUM	7	/* 16-byte typed telemetrum records */ -#define AO_LOG_FORMAT_TELEMINI		8	/* 16-byte MS5607 baro only, 3.3V supply */ +#define AO_LOG_FORMAT_TELEMINI2		8	/* 16-byte MS5607 baro only, 3.3V supply, cc1111 SoC */  #define AO_LOG_FORMAT_TELEGPS		9	/* 32 byte telegps records */  #define AO_LOG_FORMAT_TELEMEGA		10	/* 32 byte typed telemega records with 32 bit gyro cal */  #define AO_LOG_FORMAT_DETHERM		11	/* 16-byte MS5607 baro only, no ADC */ +#define AO_LOG_FORMAT_TELEMINI3		12	/* 16-byte MS5607 baro only, 3.3V supply, stm32f042 SoC */ +#define AO_LOG_FORMAT_TELEFIRETWO	13	/* 32-byte test stand data */  #define AO_LOG_FORMAT_NONE		127	/* No log at all */  extern __code uint8_t ao_log_format; @@ -299,6 +301,32 @@ struct ao_log_mega {  						 ((l)->u.gps.altitude_high = (a) >> 16), \  						 (l)->u.gps.altitude_low = (a)) +struct ao_log_firetwo { +	char			type;			/* 0 */ +	uint8_t			csum;			/* 1 */ +	uint16_t		tick;			/* 2 */ +	union {						/* 4 */ +		/* AO_LOG_FLIGHT */ +		struct { +			uint16_t	flight;		/* 4 */ +			uint16_t	idle_pressure;	/* 6 */ +			uint16_t	idle_thrust;	/* 8 */ +		} flight;	/* 16 */ +		/* AO_LOG_STATE */ +		struct { +			uint16_t	state;		/* 4 */ +			uint16_t	reason;		/* 6 */ +		} state;	/* 8 */ +		/* AO_LOG_SENSOR */ +		struct { +			uint16_t	pressure;	/* 4 */ +			uint16_t	thrust;		/* 6 */ +			uint16_t	thermistor[4];	/* 8 */ +		} sensor;	/* 24 */ +		uint8_t		align[28];		/* 4 */ +	} u;	/* 32 */ +}; +  struct ao_log_metrum {  	char			type;			/* 0 */  	uint8_t			csum;			/* 1 */ diff --git a/src/kernel/ao_log_firetwo.c b/src/kernel/ao_log_firetwo.c new file mode 100644 index 00000000..4b42abe4 --- /dev/null +++ b/src/kernel/ao_log_firetwo.c @@ -0,0 +1,149 @@ +/* + * Copyright © 2017 Bdale Garbee <bdale@gag.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" +#include <ao_log.h> +#include <ao_data.h> +#include <ao_flight.h> + +static __xdata struct ao_log_firetwo log; + +__code uint8_t ao_log_format = AO_LOG_FORMAT_TELEFIRETWO; + +static uint8_t +ao_log_csum(__xdata uint8_t *b) __reentrant +{ +	uint8_t	sum = 0x5a; +	uint8_t	i; + +	for (i = 0; i < sizeof (struct ao_log_firetwo); i++) +		sum += *b++; +	return -sum; +} + +uint8_t +ao_log_firetwo(__xdata struct ao_log_firetwo *log) __reentrant +{ +	uint8_t wrote = 0; +	/* set checksum */ +	log->csum = 0; +	log->csum = ao_log_csum((__xdata uint8_t *) log); +	ao_mutex_get(&ao_log_mutex); { +		if (ao_log_current_pos >= ao_log_end_pos && ao_log_running) +			ao_log_stop(); +		if (ao_log_running) { +			wrote = 1; +			ao_storage_write(ao_log_current_pos, +					 log, +					 sizeof (struct ao_log_firetwo)); +			ao_log_current_pos += sizeof (struct ao_log_firetwo); +		} +	} ao_mutex_put(&ao_log_mutex); +	return wrote; +} + +static uint8_t +ao_log_dump_check_data(void) +{ +	if (ao_log_csum((uint8_t *) &log) != 0) +		return 0; +	return 1; +} + +#if HAS_ADC +static __data uint8_t	ao_log_data_pos; + +/* a hack to make sure that ao_log_metrums fill the eeprom block in even units */ +typedef uint8_t check_log_size[1-(256 % sizeof(struct ao_log_firetwo))] ; +#endif + +void +ao_log(void) +{ +	uint16_t ao_idle_pressure = 0;		// write code to capture pre-test values someday +	uint16_t ao_idle_thrust = 0; +	uint16_t ao_flight_state = ao_flight_startup; + +	ao_storage_setup(); + +	do { +		ao_log_scan(); +	 +		while (!ao_log_running) +			ao_sleep(&ao_log_running); +	 +		log.type = AO_LOG_FLIGHT; +		log.tick = ao_time(); +		log.u.flight.idle_pressure = ao_idle_pressure; +		log.u.flight.idle_thrust = ao_idle_thrust; +		log.u.flight.flight = ao_flight_number; +		ao_log_firetwo(&log); + +		/* Write the whole contents of the ring to the log +	 	* when starting up. +	 	*/ +		ao_log_data_pos = ao_data_ring_next(ao_data_head); +		ao_log_state = ao_flight_startup; +		for (;;) { +			/* Write samples to EEPROM */ +			while (ao_log_data_pos != ao_data_head) { +				log.tick = ao_data_ring[ao_log_data_pos].tick; +				log.type = AO_LOG_SENSOR; +				log.u.sensor.pressure = ao_data_ring[ao_log_data_pos].adc.pressure; +				log.u.sensor.thrust = ao_data_ring[ao_log_data_pos].adc.thrust; +	//			for (i = 0; i < 4; i++) { +	//				log.u.sensor.thermistor[i] = ao_data_ring[ao_log_data_pos].sensor.thermistor[i]; +	//			} +				ao_log_firetwo(&log); +				ao_log_data_pos = ao_data_ring_next(ao_log_data_pos); +			} +			/* Write state change to EEPROM */ +			if (ao_flight_state != ao_log_state) { +				ao_log_state = ao_flight_state; +				log.type = AO_LOG_STATE; +				log.tick = ao_time(); +				log.u.state.state = ao_log_state; +				log.u.state.reason = 0; +				ao_log_firetwo(&log); +	 +				if (ao_log_state == ao_flight_landed) +					ao_log_stop(); +			} +	 +			ao_log_flush(); + +			if (!ao_log_running) break; + +			/* Wait for a while */ +			ao_delay(AO_MS_TO_TICKS(100)); +		} +	} while (ao_log_running); +} + +uint16_t +ao_log_flight(uint8_t slot) +{ +	if (!ao_storage_read(ao_log_pos(slot), +			     &log, +			     sizeof (struct ao_log_firetwo))) +		return 0; + +	if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT) +		return log.u.flight.flight; +	return 0; +} diff --git a/src/kernel/ao_pyro.c b/src/kernel/ao_pyro.c index 813e866a..a0881f9e 100644 --- a/src/kernel/ao_pyro.c +++ b/src/kernel/ao_pyro.c @@ -75,7 +75,8 @@ uint16_t	ao_pyro_fired;  #endif  #if PYRO_DBG -#define DBG(...)	do { printf("\t%d: ", (int) (pyro - ao_config.pyro)); printf(__VA_ARGS__); } while (0) +int pyro_dbg; +#define DBG(...)	do { if (pyro_dbg) printf("\t%d: ", (int) (pyro - ao_config.pyro)); printf(__VA_ARGS__); } while (0)  #else  #define DBG(...)  #endif diff --git a/src/kernel/ao_report.c b/src/kernel/ao_report.c index 6592d616..af48b390 100644 --- a/src/kernel/ao_report.c +++ b/src/kernel/ao_report.c @@ -45,9 +45,16 @@ static const uint8_t flight_reports[] = {  #define mid(time)	ao_beep_for(AO_BEEP_MID, time)  #define high(time)	ao_beep_for(AO_BEEP_HIGH, time)  #else -#define low(time)	ao_led_for(AO_LED_GREEN, time) -#define mid(time)	ao_led_for(AO_LED_RED, time) -#define high(time)	ao_led_for(AO_LED_GREEN|AO_LED_RED, time) +#ifndef AO_LED_LOW +#define AO_LED_LOW	AO_LED_GREEN +#endif +#ifndef AO_LED_MID +#define AO_LED_MID	AO_LED_RED +#endif + +#define low(time)	ao_led_for(AO_LED_LOW, time) +#define mid(time)	ao_led_for(AO_LED_MID, time) +#define high(time)	ao_led_for(AO_LED_MID|AO_LED_LOW, time)  #endif  #define pause(time)	ao_delay(time) diff --git a/src/kernel/ao_stdio.c b/src/kernel/ao_stdio.c index b79d465a..f0ee0a14 100644 --- a/src/kernel/ao_stdio.c +++ b/src/kernel/ao_stdio.c @@ -55,6 +55,9 @@  #ifndef PACKET_HAS_SLAVE  #define PACKET_HAS_SLAVE	0  #endif +#ifndef CONSOLE_STDIN +#define CONSOLE_STDIN		0 +#endif  #define USE_SERIAL_STDIN (USE_SERIAL_0_STDIN +	\  			  USE_SERIAL_1_STDIN +	\ @@ -67,7 +70,7 @@  			  USE_SERIAL_8_STDIN +	\  			  USE_SERIAL_9_STDIN) -#define AO_NUM_STDIOS	(HAS_USB + PACKET_HAS_SLAVE + USE_SERIAL_STDIN) +#define AO_NUM_STDIOS	(HAS_USB + PACKET_HAS_SLAVE + USE_SERIAL_STDIN + CONSOLE_STDIN)  __xdata struct ao_stdio ao_stdios[AO_NUM_STDIOS]; diff --git a/src/kernel/ao_task.c b/src/kernel/ao_task.c index e8a092aa..de23ea02 100644 --- a/src/kernel/ao_task.c +++ b/src/kernel/ao_task.c @@ -373,7 +373,11 @@ ao_yield(void) ao_arch_naked_define  		if (!ao_list_is_empty(&run_queue))  			break;  		/* Wait for interrupts when there's nothing ready */ -		ao_arch_wait_interrupt(); +		if (ao_task_minimize_latency) { +			ao_arch_release_interrupts(); +			ao_arch_block_interrupts(); +		} else +			ao_arch_wait_interrupt();  	}  	ao_cur_task = ao_list_first_entry(&run_queue, struct ao_task, queue);  #else diff --git a/src/kernel/ao_telemetry.c b/src/kernel/ao_telemetry.c index 15085bf4..fa817824 100644 --- a/src/kernel/ao_telemetry.c +++ b/src/kernel/ao_telemetry.c @@ -270,7 +270,7 @@ ao_send_mini(void)  	__xdata	struct ao_data *packet = (__xdata struct ao_data *) &ao_data_ring[ao_data_ring_prev(ao_sample_data)];  	telemetry.generic.tick = packet->tick; -	telemetry.generic.type = AO_TELEMETRY_MINI; +	telemetry.generic.type = AO_SEND_MINI;  	telemetry.mini.state = ao_flight_state; diff --git a/src/kernel/ao_telemetry.h b/src/kernel/ao_telemetry.h index c0f5e3c5..45aaeb07 100644 --- a/src/kernel/ao_telemetry.h +++ b/src/kernel/ao_telemetry.h @@ -270,7 +270,8 @@ struct ao_telemetry_metrum_data {  	/* 32 */  }; -#define AO_TELEMETRY_MINI		0x10 +#define AO_TELEMETRY_MINI2		0x10	/* CC1111 based */ +#define AO_TELEMETRY_MINI3		0x11	/* STMF042 based */  struct ao_telemetry_mini {  	uint16_t	serial;		/*  0 */ diff --git a/src/lambdakey-v1.0/.gitignore b/src/lambdakey-v1.0/.gitignore new file mode 100644 index 00000000..6462d930 --- /dev/null +++ b/src/lambdakey-v1.0/.gitignore @@ -0,0 +1,2 @@ +lambdakey-* +ao_product.h diff --git a/src/lambdakey-v1.0/Makefile b/src/lambdakey-v1.0/Makefile new file mode 100644 index 00000000..2609bea3 --- /dev/null +++ b/src/lambdakey-v1.0/Makefile @@ -0,0 +1,92 @@ +# +# AltOS build +# +# + +include ../stmf0/Makefile.defs + +INC = \ +	ao.h \ +	ao_arch.h \ +	ao_arch_funcs.h \ +	ao_boot.h \ +	ao_pins.h \ +	ao_product.h \ +	ao_task.h \ +	ao_lisp.h \ +	ao_lisp_const.h \ +	ao_lisp_os.h \ +	stm32f0.h \ +	Makefile + +ALTOS_SRC = \ +	ao_boot_chain.c \ +	ao_interrupt.c \ +	ao_product.c \ +	ao_romconfig.c \ +	ao_cmd.c \ +	ao_config.c \ +	ao_task.c \ +	ao_led.c \ +	ao_dma_stm.c \ +	ao_stdio.c \ +	ao_mutex.c \ +	ao_panic.c \ +	ao_timer.c \ +	ao_usb_stm.c \ +	ao_flash_stm.c \ +	ao_lisp_lex.c \ +	ao_lisp_mem.c \ +	ao_lisp_cons.c \ +	ao_lisp_eval.c \ +	ao_lisp_string.c \ +	ao_lisp_atom.c \ +	ao_lisp_int.c \ +	ao_lisp_poly.c \ +	ao_lisp_builtin.c \ +	ao_lisp_read.c \ +	ao_lisp_rep.c \ +	ao_lisp_frame.c \ +	ao_lisp_error.c \ +	ao_lisp_lambda.c \ +	ao_lisp_save.c \ +	ao_lisp_stack.c \ +	ao_lisp_os_save.c + +PRODUCT=LambdaKey-v1.0 +PRODUCT_DEF=-DLAMBDAKEY +IDPRODUCT=0x000a + +CFLAGS = $(PRODUCT_DEF) -I. $(STMF0_CFLAGS) -Os -g + +LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Tlambda.ld + +PROGNAME=lambdakey-v1.0 +PROG=$(PROGNAME)-$(VERSION).elf +HEX=$(PROGNAME)-$(VERSION).ihx + +SRC=$(ALTOS_SRC) ao_lambdakey.c +OBJ=$(SRC:.c=.o) + +all: $(PROG) $(HEX) + +$(PROG): Makefile $(OBJ) lambda.ld altos.ld +	$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) + +$(OBJ): $(INC) + +ao_product.h: ao-make-product.5c ../Version +	$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +load: $(PROG) +	stm-load $(PROG) + +distclean:	clean + +clean: +	rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx +	rm -f ao_product.h + +install: + +uninstall: diff --git a/src/lambdakey-v1.0/ao_lambdakey.c b/src/lambdakey-v1.0/ao_lambdakey.c new file mode 100644 index 00000000..8bd344cf --- /dev/null +++ b/src/lambdakey-v1.0/ao_lambdakey.c @@ -0,0 +1,41 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <ao.h> +#include <ao_lisp.h> + +static void lisp_cmd() { +	ao_lisp_read_eval_print(); +} + +static const struct ao_cmds blink_cmds[] = { +	{ lisp_cmd,	"l\0Run lisp interpreter" }, +	{ 0, 0 } +}; + + +void main(void) +{ +	ao_led_init(LEDS_AVAILABLE); +	ao_clock_init(); +	ao_task_init(); +	ao_timer_init(); +	ao_dma_init(); +	ao_usb_init(); +	ao_cmd_init(); +	ao_cmd_register(blink_cmds); +	ao_start_scheduler(); +} + + diff --git a/src/lambdakey-v1.0/ao_lisp_os.h b/src/lambdakey-v1.0/ao_lisp_os.h new file mode 100644 index 00000000..1993ac44 --- /dev/null +++ b/src/lambdakey-v1.0/ao_lisp_os.h @@ -0,0 +1,62 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_LISP_OS_H_ +#define _AO_LISP_OS_H_ + +#include "ao.h" + +static inline int +ao_lisp_getc() { +	static uint8_t	at_eol; +	int c; + +	if (at_eol) { +		ao_cmd_readline(); +		at_eol = 0; +	} +	c = ao_cmd_lex(); +	if (c == '\n') +		at_eol = 1; +	return c; +} + +static inline void +ao_lisp_os_flush(void) +{ +	flush(); +} + +static inline void +ao_lisp_abort(void) +{ +	ao_panic(1); +} + +static inline void +ao_lisp_os_led(int led) +{ +	ao_led_set(led); +} + +static inline void +ao_lisp_os_delay(int delay) +{ +	ao_delay(AO_MS_TO_TICKS(delay)); +} + +#endif diff --git a/src/lambdakey-v1.0/ao_lisp_os_save.c b/src/lambdakey-v1.0/ao_lisp_os_save.c new file mode 100644 index 00000000..44138398 --- /dev/null +++ b/src/lambdakey-v1.0/ao_lisp_os_save.c @@ -0,0 +1,53 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <ao.h> +#include <ao_lisp.h> +#include <ao_flash.h> + +extern uint8_t	__flash__[]; + +/* saved variables to rebuild the heap + +   ao_lisp_atoms +   ao_lisp_frame_global + */ + +int +ao_lisp_os_save(void) +{ +	int i; + +	for (i = 0; i < AO_LISP_POOL_TOTAL; i += 256) { +		uint32_t	*dst = (uint32_t *) &__flash__[i]; +		uint32_t	*src = (uint32_t *) &ao_lisp_pool[i]; + +		ao_flash_page(dst, src); +	} +	return 1; +} + +int +ao_lisp_os_restore_save(struct ao_lisp_os_save *save, int offset) +{ +	memcpy(save, &__flash__[offset], sizeof (struct ao_lisp_os_save)); +	return 1; +} + +int +ao_lisp_os_restore(void) +{ +	memcpy(ao_lisp_pool, __flash__, AO_LISP_POOL_TOTAL); +	return 1; +} diff --git a/src/lambdakey-v1.0/ao_pins.h b/src/lambdakey-v1.0/ao_pins.h new file mode 100644 index 00000000..2ba79c01 --- /dev/null +++ b/src/lambdakey-v1.0/ao_pins.h @@ -0,0 +1,57 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#define LED_PORT_ENABLE	STM_RCC_AHBENR_IOPBEN +#define LED_PORT	(&stm_gpiob) +#define LED_PIN_RED	4 +#define AO_LED_RED	(1 << LED_PIN_RED) +#define AO_LED_PANIC	AO_LED_RED +#define AO_CMD_LEN	128 +#define AO_LISP_POOL_TOTAL	3072 +#define AO_LISP_SAVE	1 +#define AO_STACK_SIZE	1024 + +/* need HSI active to write to flash */ +#define AO_NEED_HSI	1 + +#define LEDS_AVAILABLE	(AO_LED_RED) + +#define AO_POWER_MANAGEMENT	0 + +/* 48MHz clock based on USB */ +#define AO_HSI48	1 + +/* HCLK = 48MHz */ +#define AO_AHB_PRESCALER	1 +#define AO_RCC_CFGR_HPRE_DIV	STM_RCC_CFGR_HPRE_DIV_1 + +/* APB = 48MHz */ +#define AO_APB_PRESCALER	1 +#define AO_RCC_CFGR_PPRE_DIV	STM_RCC_CFGR_PPRE_DIV_1 + +#define HAS_USB				1 +#define AO_USB_DIRECTIO			0 +#define AO_PA11_PA12_RMP		1 +#define HAS_BEEP			0 + +#define IS_FLASH_LOADER	0 + +#endif /* _AO_PINS_H_ */ diff --git a/src/lambdakey-v1.0/flash-loader/.gitignore b/src/lambdakey-v1.0/flash-loader/.gitignore new file mode 100644 index 00000000..86ebb7f2 --- /dev/null +++ b/src/lambdakey-v1.0/flash-loader/.gitignore @@ -0,0 +1,2 @@ +ao_product.h +lambdakey* diff --git a/src/lambdakey-v1.0/flash-loader/Makefile b/src/lambdakey-v1.0/flash-loader/Makefile new file mode 100644 index 00000000..dbded719 --- /dev/null +++ b/src/lambdakey-v1.0/flash-loader/Makefile @@ -0,0 +1,8 @@ +# +# AltOS flash loader build +# +# + +TOPDIR=../.. +HARDWARE=lambdakey-v1.0 +include $(TOPDIR)/stmf0/Makefile-flash.defs diff --git a/src/lambdakey-v1.0/flash-loader/ao_pins.h b/src/lambdakey-v1.0/flash-loader/ao_pins.h new file mode 100644 index 00000000..4b788f67 --- /dev/null +++ b/src/lambdakey-v1.0/flash-loader/ao_pins.h @@ -0,0 +1,37 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#include <ao_flash_stm_pins.h> + +/* Pin 5 on debug connector */ + +#define AO_BOOT_PIN			1 +#define AO_BOOT_APPLICATION_GPIO	stm_gpioa +#define AO_BOOT_APPLICATION_PIN		15 +#define AO_BOOT_APPLICATION_VALUE	1 +#define AO_BOOT_APPLICATION_MODE	AO_EXTI_MODE_PULL_UP + +/* USB */ +#define HAS_USB			1 +#define AO_USB_DIRECTIO		0 +#define AO_PA11_PA12_RMP	1 + +#endif /* _AO_PINS_H_ */ diff --git a/src/lambdakey-v1.0/lambda.ld b/src/lambdakey-v1.0/lambda.ld new file mode 100644 index 00000000..5de65eb5 --- /dev/null +++ b/src/lambdakey-v1.0/lambda.ld @@ -0,0 +1,117 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +MEMORY { +	rom (rx) :   ORIGIN = 0x08001000, LENGTH = 25K +	flash (r):   ORIGIN = 0x08007400, LENGTH = 3k +	ram (!w) :   ORIGIN = 0x20000000, LENGTH = 6k - 128 +	stack (!w) : ORIGIN = 0x20000000 + 6k - 128, LENGTH = 128 +} + +INCLUDE registers.ld + +EXTERN (stm_interrupt_vector) + +SECTIONS { +	/* +	 * Rom contents +	 */ + +	.interrupt ORIGIN(ram) : AT (ORIGIN(rom)) { +		__interrupt_start__ = .; +		__interrupt_rom__ = ORIGIN(rom); +		*(.interrupt)	/* Interrupt vectors */ +		__interrupt_end__ = .; +	} > ram + +	.text ORIGIN(rom) + 0x100 : { +		__text_start__ = .; + +		/* Ick. What I want is to specify the +		 * addresses of some global constants so +		 * that I can find them across versions +		 * of the application. I can't figure out +		 * how to make gnu ld do that, so instead +		 * we just load the two files that include +		 * these defines in the right order here and +		 * expect things to 'just work'. Don't change +		 * the contents of those files, ok? +		 */ +		ao_romconfig.o(.romconfig*) +		ao_product.o(.romconfig*) + +		*(.text*)	/* Executable code */ +		*(.ARM.exidx* .gnu.linkonce.armexidx.*) +		*(.rodata*)	/* Constants */ + +	} > rom +	__text_end__ = .; +	 + +	/* Boot data which must live at the start of ram so that +	 * the application and bootloader share the same addresses. +	 * This must be all uninitialized data +	 */ +	.boot (NOLOAD) : { +		__boot_start__ = .; +		*(.boot) +		. = ALIGN(4); +		__boot_end__ = .; +	} >ram + +	/* Functions placed in RAM (required for flashing) +	 * +	 * Align to 8 bytes as that's what the ARM likes text +	 * segment alignments to be, and if we don't, then +	 * we end up with a mismatch between the location in +	 * ROM and the desired location in RAM. I don't +	 * entirely understand this, but at least this appears +	 * to work... +	 */ + +	.textram BLOCK(8): { +		__data_start__ = .; +		__text_ram_start__ = .; +		*(.ramtext) +		__text_ram_end = .; +	} >ram AT>rom + +	/* Data -- relocated to RAM, but written to ROM +	 */ +	.data : { +		*(.data)	/* initialized data */ +		. = ALIGN(4); +		__data_end__ = .; +	} >ram AT>rom + +	.bss : { +		__bss_start__ = .; +		*(.bss) +		*(COMMON) +		. = ALIGN(4); +		__bss_end__ = .; +	} >ram + +	PROVIDE(end = .); + +	PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack)); + +	__flash__ = ORIGIN(flash); +} + +ENTRY(start); diff --git a/src/lisp/.gitignore b/src/lisp/.gitignore new file mode 100644 index 00000000..76a555ea --- /dev/null +++ b/src/lisp/.gitignore @@ -0,0 +1,2 @@ +ao_lisp_make_const +ao_lisp_const.h diff --git a/src/lisp/Makefile b/src/lisp/Makefile new file mode 100644 index 00000000..25796ec5 --- /dev/null +++ b/src/lisp/Makefile @@ -0,0 +1,22 @@ +all: ao_lisp_const.h + +clean: +	rm -f ao_lisp_const.h $(OBJS) ao_lisp_make_const + +ao_lisp_const.h: ao_lisp_const.lisp ao_lisp_make_const +	./ao_lisp_make_const -o $@ ao_lisp_const.lisp + +include Makefile-inc +SRCS=$(LISP_SRCS) + +HDRS=$(LISP_HDRS) + +OBJS=$(SRCS:.c=.o) + +CFLAGS=-DAO_LISP_MAKE_CONST -O0 -g -I. -Wall -Wextra -no-pie + + +ao_lisp_make_const:  $(OBJS) +	$(CC) $(CFLAGS) -o $@ $(OBJS) + +$(OBJS): $(HDRS) diff --git a/src/lisp/Makefile-inc b/src/lisp/Makefile-inc new file mode 100644 index 00000000..126deeb0 --- /dev/null +++ b/src/lisp/Makefile-inc @@ -0,0 +1,22 @@ +LISP_SRCS=\ +	ao_lisp_make_const.c\ +	ao_lisp_mem.c \ +	ao_lisp_cons.c \ +	ao_lisp_string.c \ +	ao_lisp_atom.c \ +	ao_lisp_int.c \ +	ao_lisp_poly.c \ +	ao_lisp_builtin.c \ +	ao_lisp_read.c \ +	ao_lisp_frame.c \ +	ao_lisp_lambda.c \ +	ao_lisp_eval.c \ +	ao_lisp_rep.c \ +	ao_lisp_save.c \ +	ao_lisp_stack.c \ +	ao_lisp_error.c  + +LISP_HDRS=\ +	ao_lisp.h \ +	ao_lisp_os.h \ +	ao_lisp_read.h diff --git a/src/lisp/Makefile-lisp b/src/lisp/Makefile-lisp new file mode 100644 index 00000000..998c7673 --- /dev/null +++ b/src/lisp/Makefile-lisp @@ -0,0 +1,4 @@ +include ../lisp/Makefile-inc + +ao_lisp_const.h: $(LISP_SRCS) $(LISP_HDRS) +	+cd ../lisp && make $@ diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h new file mode 100644 index 00000000..980514cc --- /dev/null +++ b/src/lisp/ao_lisp.h @@ -0,0 +1,793 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef _AO_LISP_H_ +#define _AO_LISP_H_ + +#define DBG_MEM		0 +#define DBG_EVAL	0 + +#include <stdint.h> +#include <string.h> +#include <ao_lisp_os.h> + +typedef uint16_t	ao_poly; +typedef int16_t		ao_signed_poly; + +#ifdef AO_LISP_SAVE + +struct ao_lisp_os_save { +	ao_poly		atoms; +	ao_poly		globals; +	uint16_t	const_checksum; +	uint16_t	const_checksum_inv; +}; + +#define AO_LISP_POOL_EXTRA	(sizeof(struct ao_lisp_os_save)) +#define AO_LISP_POOL	((int) (AO_LISP_POOL_TOTAL - AO_LISP_POOL_EXTRA)) + +int +ao_lisp_os_save(void); + +int +ao_lisp_os_restore_save(struct ao_lisp_os_save *save, int offset); + +int +ao_lisp_os_restore(void); + +#endif + +#ifdef AO_LISP_MAKE_CONST +#define AO_LISP_POOL_CONST	16384 +extern uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4))); +#define ao_lisp_pool ao_lisp_const +#define AO_LISP_POOL AO_LISP_POOL_CONST + +#define _atom(n) ao_lisp_atom_poly(ao_lisp_atom_intern(n)) + +#define _ao_lisp_atom_quote	_atom("quote") +#define _ao_lisp_atom_set 	_atom("set") +#define _ao_lisp_atom_setq 	_atom("setq") +#define _ao_lisp_atom_t 	_atom("t") +#define _ao_lisp_atom_car 	_atom("car") +#define _ao_lisp_atom_cdr	_atom("cdr") +#define _ao_lisp_atom_cons	_atom("cons") +#define _ao_lisp_atom_last	_atom("last") +#define _ao_lisp_atom_length	_atom("length") +#define _ao_lisp_atom_cond	_atom("cond") +#define _ao_lisp_atom_lambda	_atom("lambda") +#define _ao_lisp_atom_led	_atom("led") +#define _ao_lisp_atom_delay	_atom("delay") +#define _ao_lisp_atom_pack	_atom("pack") +#define _ao_lisp_atom_unpack	_atom("unpack") +#define _ao_lisp_atom_flush	_atom("flush") +#define _ao_lisp_atom_eval	_atom("eval") +#define _ao_lisp_atom_read	_atom("read") +#define _ao_lisp_atom_eof	_atom("eof") +#define _ao_lisp_atom_save	_atom("save") +#define _ao_lisp_atom_restore	_atom("restore") +#define _ao_lisp_atom_call2fcc	_atom("call/cc") +#define _ao_lisp_atom_collect	_atom("collect") +#define _ao_lisp_atom_symbolp   _atom("symbol?") +#define _ao_lisp_atom_builtin   _atom("builtin?") +#define _ao_lisp_atom_symbolp   _atom("symbol?") +#define _ao_lisp_atom_symbolp   _atom("symbol?") +#else +#include "ao_lisp_const.h" +#ifndef AO_LISP_POOL +#define AO_LISP_POOL	3072 +#endif +extern uint8_t		ao_lisp_pool[AO_LISP_POOL + AO_LISP_POOL_EXTRA] __attribute__((aligned(4))); +#endif + +/* Primitive types */ +#define AO_LISP_CONS		0 +#define AO_LISP_INT		1 +#define AO_LISP_STRING		2 +#define AO_LISP_OTHER		3 + +#define AO_LISP_TYPE_MASK	0x0003 +#define AO_LISP_TYPE_SHIFT	2 +#define AO_LISP_REF_MASK	0x7ffc +#define AO_LISP_CONST		0x8000 + +/* These have a type value at the start of the struct */ +#define AO_LISP_ATOM		4 +#define AO_LISP_BUILTIN		5 +#define AO_LISP_FRAME		6 +#define AO_LISP_LAMBDA		7 +#define AO_LISP_STACK		8 +#define AO_LISP_NUM_TYPE	9 + +/* Leave two bits for types to use as they please */ +#define AO_LISP_OTHER_TYPE_MASK	0x3f + +#define AO_LISP_NIL	0 + +extern uint16_t		ao_lisp_top; + +#define AO_LISP_OOM		0x01 +#define AO_LISP_DIVIDE_BY_ZERO	0x02 +#define AO_LISP_INVALID		0x04 +#define AO_LISP_UNDEFINED	0x08 +#define AO_LISP_EOF		0x10 + +extern uint8_t		ao_lisp_exception; + +static inline int +ao_lisp_is_const(ao_poly poly) { +	return poly & AO_LISP_CONST; +} + +#define AO_LISP_IS_CONST(a)	(ao_lisp_const <= ((uint8_t *) (a)) && ((uint8_t *) (a)) < ao_lisp_const + AO_LISP_POOL_CONST) +#define AO_LISP_IS_POOL(a)	(ao_lisp_pool <= ((uint8_t *) (a)) && ((uint8_t *) (a)) < ao_lisp_pool + AO_LISP_POOL) +#define AO_LISP_IS_INT(p)	(ao_lisp_base_type(p) == AO_LISP_INT); + +void * +ao_lisp_ref(ao_poly poly); + +ao_poly +ao_lisp_poly(const void *addr, ao_poly type); + +struct ao_lisp_type { +	int	(*size)(void *addr); +	void	(*mark)(void *addr); +	void	(*move)(void *addr); +	char	name[]; +}; + +struct ao_lisp_cons { +	ao_poly		car; +	ao_poly		cdr; +}; + +struct ao_lisp_atom { +	uint8_t		type; +	uint8_t		pad[1]; +	ao_poly		next; +	char		name[]; +}; + +struct ao_lisp_val { +	ao_poly		atom; +	ao_poly		val; +}; + +struct ao_lisp_frame { +	uint8_t			type; +	uint8_t			num; +	ao_poly			prev; +	struct ao_lisp_val	vals[]; +}; + +/* Set on type when the frame escapes the lambda */ +#define AO_LISP_FRAME_MARK	0x80 +#define AO_LISP_FRAME_PRINT	0x40 + +static inline int ao_lisp_frame_marked(struct ao_lisp_frame *f) { +	return f->type & AO_LISP_FRAME_MARK; +} + +static inline struct ao_lisp_frame * +ao_lisp_poly_frame(ao_poly poly) { +	return ao_lisp_ref(poly); +} + +static inline ao_poly +ao_lisp_frame_poly(struct ao_lisp_frame *frame) { +	return ao_lisp_poly(frame, AO_LISP_OTHER); +} + +enum eval_state { +	eval_sexpr,		/* Evaluate an sexpr */ +	eval_val,		/* Value computed */ +	eval_formal,		/* Formal computed */ +	eval_exec,		/* Start a lambda evaluation */ +	eval_cond,		/* Start next cond clause */ +	eval_cond_test,		/* Check cond condition */ +	eval_progn,		/* Start next progn entry */ +	eval_while,		/* Start while condition */ +	eval_while_test,	/* Check while condition */ +	eval_macro,		/* Finished with macro generation */ +}; + +struct ao_lisp_stack { +	uint8_t			type;		/* AO_LISP_STACK */ +	uint8_t			state;		/* enum eval_state */ +	ao_poly			prev;		/* previous stack frame */ +	ao_poly			sexprs;		/* expressions to evaluate */ +	ao_poly			values;		/* values computed */ +	ao_poly			values_tail;	/* end of the values list for easy appending */ +	ao_poly			frame;		/* current lookup frame */ +	ao_poly			list;		/* most recent function call */ +}; + +#define AO_LISP_STACK_MARK	0x80	/* set on type when a reference has been taken */ +#define AO_LISP_STACK_PRINT	0x40	/* stack is being printed */ + +static inline int ao_lisp_stack_marked(struct ao_lisp_stack *s) { +	return s->type & AO_LISP_STACK_MARK; +} + +static inline void ao_lisp_stack_mark(struct ao_lisp_stack *s) { +	s->type |= AO_LISP_STACK_MARK; +} + +static inline struct ao_lisp_stack * +ao_lisp_poly_stack(ao_poly p) +{ +	return ao_lisp_ref(p); +} + +static inline ao_poly +ao_lisp_stack_poly(struct ao_lisp_stack *stack) +{ +	return ao_lisp_poly(stack, AO_LISP_OTHER); +} + +extern ao_poly			ao_lisp_v; + +#define AO_LISP_FUNC_LAMBDA	0 +#define AO_LISP_FUNC_NLAMBDA	1 +#define AO_LISP_FUNC_MACRO	2 +#define AO_LISP_FUNC_LEXPR	3 + +#define AO_LISP_FUNC_FREE_ARGS	0x80 +#define AO_LISP_FUNC_MASK	0x7f + +#define AO_LISP_FUNC_F_LAMBDA	(AO_LISP_FUNC_FREE_ARGS | AO_LISP_FUNC_LAMBDA) +#define AO_LISP_FUNC_F_NLAMBDA	(AO_LISP_FUNC_FREE_ARGS | AO_LISP_FUNC_NLAMBDA) +#define AO_LISP_FUNC_F_MACRO	(AO_LISP_FUNC_FREE_ARGS | AO_LISP_FUNC_MACRO) +#define AO_LISP_FUNC_F_LEXPR	(AO_LISP_FUNC_FREE_ARGS | AO_LISP_FUNC_LEXPR) + +struct ao_lisp_builtin { +	uint8_t		type; +	uint8_t		args; +	uint16_t	func; +}; + +enum ao_lisp_builtin_id { +	builtin_eval, +	builtin_read, +	builtin_lambda, +	builtin_lexpr, +	builtin_nlambda, +	builtin_macro, +	builtin_car, +	builtin_cdr, +	builtin_cons, +	builtin_last, +	builtin_length, +	builtin_quote, +	builtin_set, +	builtin_setq, +	builtin_cond, +	builtin_progn, +	builtin_while, +	builtin_print, +	builtin_patom, +	builtin_plus, +	builtin_minus, +	builtin_times, +	builtin_divide, +	builtin_mod, +	builtin_equal, +	builtin_less, +	builtin_greater, +	builtin_less_equal, +	builtin_greater_equal, +	builtin_pack, +	builtin_unpack, +	builtin_flush, +	builtin_delay, +	builtin_led, +	builtin_save, +	builtin_restore, +	builtin_call_cc, +	builtin_collect, +	_builtin_last +}; + +typedef ao_poly (*ao_lisp_func_t)(struct ao_lisp_cons *cons); + +extern const ao_lisp_func_t	ao_lisp_builtins[]; + +static inline ao_lisp_func_t +ao_lisp_func(struct ao_lisp_builtin *b) +{ +	return ao_lisp_builtins[b->func]; +} + +struct ao_lisp_lambda { +	uint8_t		type; +	uint8_t		args; +	ao_poly		code; +	ao_poly		frame; +}; + +static inline struct ao_lisp_lambda * +ao_lisp_poly_lambda(ao_poly poly) +{ +	return ao_lisp_ref(poly); +} + +static inline ao_poly +ao_lisp_lambda_poly(struct ao_lisp_lambda *lambda) +{ +	return ao_lisp_poly(lambda, AO_LISP_OTHER); +} + +static inline void * +ao_lisp_poly_other(ao_poly poly) { +	return ao_lisp_ref(poly); +} + +static inline uint8_t +ao_lisp_other_type(void *other) { +#if DBG_MEM +	if ((*((uint8_t *) other) & AO_LISP_OTHER_TYPE_MASK) >= AO_LISP_NUM_TYPE) +		ao_lisp_abort(); +#endif +	return *((uint8_t *) other) & AO_LISP_OTHER_TYPE_MASK; +} + +static inline ao_poly +ao_lisp_other_poly(const void *other) +{ +	return ao_lisp_poly(other, AO_LISP_OTHER); +} + +static inline int +ao_lisp_size_round(int size) +{ +	return (size + 3) & ~3; +} + +static inline int +ao_lisp_size(const struct ao_lisp_type *type, void *addr) +{ +	return ao_lisp_size_round(type->size(addr)); +} + +#define AO_LISP_OTHER_POLY(other) ((ao_poly)(other) + AO_LISP_OTHER) + +static inline int ao_lisp_poly_base_type(ao_poly poly) { +	return poly & AO_LISP_TYPE_MASK; +} + +static inline int ao_lisp_poly_type(ao_poly poly) { +	int	type = poly & AO_LISP_TYPE_MASK; +	if (type == AO_LISP_OTHER) +		return ao_lisp_other_type(ao_lisp_poly_other(poly)); +	return type; +} + +static inline struct ao_lisp_cons * +ao_lisp_poly_cons(ao_poly poly) +{ +	return ao_lisp_ref(poly); +} + +static inline ao_poly +ao_lisp_cons_poly(struct ao_lisp_cons *cons) +{ +	return ao_lisp_poly(cons, AO_LISP_CONS); +} + +static inline int +ao_lisp_poly_int(ao_poly poly) +{ +	return (int) ((ao_signed_poly) poly >> AO_LISP_TYPE_SHIFT); +} + +static inline ao_poly +ao_lisp_int_poly(int i) +{ +	return ((ao_poly) i << 2) | AO_LISP_INT; +} + +static inline char * +ao_lisp_poly_string(ao_poly poly) +{ +	return ao_lisp_ref(poly); +} + +static inline ao_poly +ao_lisp_string_poly(char *s) +{ +	return ao_lisp_poly(s, AO_LISP_STRING); +} + +static inline struct ao_lisp_atom * +ao_lisp_poly_atom(ao_poly poly) +{ +	return ao_lisp_ref(poly); +} + +static inline ao_poly +ao_lisp_atom_poly(struct ao_lisp_atom *a) +{ +	return ao_lisp_poly(a, AO_LISP_OTHER); +} + +static inline struct ao_lisp_builtin * +ao_lisp_poly_builtin(ao_poly poly) +{ +	return ao_lisp_ref(poly); +} + +static inline ao_poly +ao_lisp_builtin_poly(struct ao_lisp_builtin *b) +{ +	return ao_lisp_poly(b, AO_LISP_OTHER); +} + +/* memory functions */ + +extern int ao_lisp_collects[2]; +extern int ao_lisp_freed[2]; +extern int ao_lisp_loops[2]; + +/* returns 1 if the object was already marked */ +int +ao_lisp_mark(const struct ao_lisp_type *type, void *addr); + +/* returns 1 if the object was already marked */ +int +ao_lisp_mark_memory(const struct ao_lisp_type *type, void *addr); + +void * +ao_lisp_move_map(void *addr); + +/* returns 1 if the object was already moved */ +int +ao_lisp_move(const struct ao_lisp_type *type, void **ref); + +/* returns 1 if the object was already moved */ +int +ao_lisp_move_memory(const struct ao_lisp_type *type, void **ref); + +void * +ao_lisp_alloc(int size); + +#define AO_LISP_COLLECT_FULL		1 +#define AO_LISP_COLLECT_INCREMENTAL	0 + +int +ao_lisp_collect(uint8_t style); + +void +ao_lisp_cons_stash(int id, struct ao_lisp_cons *cons); + +struct ao_lisp_cons * +ao_lisp_cons_fetch(int id); + +void +ao_lisp_poly_stash(int id, ao_poly poly); + +ao_poly +ao_lisp_poly_fetch(int id); + +void +ao_lisp_string_stash(int id, char *string); + +char * +ao_lisp_string_fetch(int id); + +static inline void +ao_lisp_stack_stash(int id, struct ao_lisp_stack *stack) { +	ao_lisp_poly_stash(id, ao_lisp_stack_poly(stack)); +} + +static inline struct ao_lisp_stack * +ao_lisp_stack_fetch(int id) { +	return ao_lisp_poly_stack(ao_lisp_poly_fetch(id)); +} + +/* cons */ +extern const struct ao_lisp_type ao_lisp_cons_type; + +struct ao_lisp_cons * +ao_lisp_cons_cons(ao_poly car, struct ao_lisp_cons *cdr); + +extern struct ao_lisp_cons *ao_lisp_cons_free_list; + +void +ao_lisp_cons_free(struct ao_lisp_cons *cons); + +void +ao_lisp_cons_print(ao_poly); + +void +ao_lisp_cons_patom(ao_poly); + +int +ao_lisp_cons_length(struct ao_lisp_cons *cons); + +/* string */ +extern const struct ao_lisp_type ao_lisp_string_type; + +char * +ao_lisp_string_copy(char *a); + +char * +ao_lisp_string_cat(char *a, char *b); + +ao_poly +ao_lisp_string_pack(struct ao_lisp_cons *cons); + +ao_poly +ao_lisp_string_unpack(char *a); + +void +ao_lisp_string_print(ao_poly s); + +void +ao_lisp_string_patom(ao_poly s); + +/* atom */ +extern const struct ao_lisp_type ao_lisp_atom_type; + +extern struct ao_lisp_atom	*ao_lisp_atoms; +extern struct ao_lisp_frame	*ao_lisp_frame_global; +extern struct ao_lisp_frame	*ao_lisp_frame_current; + +void +ao_lisp_atom_print(ao_poly a); + +struct ao_lisp_atom * +ao_lisp_atom_intern(char *name); + +ao_poly * +ao_lisp_atom_ref(struct ao_lisp_frame *frame, ao_poly atom); + +ao_poly +ao_lisp_atom_get(ao_poly atom); + +ao_poly +ao_lisp_atom_set(ao_poly atom, ao_poly val); + +/* int */ +void +ao_lisp_int_print(ao_poly i); + +/* prim */ +void +ao_lisp_poly_print(ao_poly p); + +void +ao_lisp_poly_patom(ao_poly p); + +int +ao_lisp_poly_mark(ao_poly p, uint8_t note_cons); + +/* returns 1 if the object has already been moved */ +int +ao_lisp_poly_move(ao_poly *p, uint8_t note_cons); + +/* eval */ + +void +ao_lisp_eval_clear_globals(void); + +int +ao_lisp_eval_restart(void); + +ao_poly +ao_lisp_eval(ao_poly p); + +ao_poly +ao_lisp_set_cond(struct ao_lisp_cons *cons); + +/* builtin */ +void +ao_lisp_builtin_print(ao_poly b); + +extern const struct ao_lisp_type ao_lisp_builtin_type; + +/* Check argument count */ +ao_poly +ao_lisp_check_argc(ao_poly name, struct ao_lisp_cons *cons, int min, int max); + +/* Check argument type */ +ao_poly +ao_lisp_check_argt(ao_poly name, struct ao_lisp_cons *cons, int argc, int type, int nil_ok); + +/* Fetch an arg (nil if off the end) */ +ao_poly +ao_lisp_arg(struct ao_lisp_cons *cons, int argc); + +char * +ao_lisp_args_name(uint8_t args); + +/* read */ +extern struct ao_lisp_cons	*ao_lisp_read_cons; +extern struct ao_lisp_cons	*ao_lisp_read_cons_tail; +extern struct ao_lisp_cons	*ao_lisp_read_stack; + +ao_poly +ao_lisp_read(void); + +/* rep */ +ao_poly +ao_lisp_read_eval_print(void); + +/* frame */ +extern const struct ao_lisp_type ao_lisp_frame_type; + +#define AO_LISP_FRAME_FREE	6 + +extern struct ao_lisp_frame	*ao_lisp_frame_free_list[AO_LISP_FRAME_FREE]; + +ao_poly +ao_lisp_frame_mark(struct ao_lisp_frame *frame); + +ao_poly * +ao_lisp_frame_ref(struct ao_lisp_frame *frame, ao_poly atom); + +struct ao_lisp_frame * +ao_lisp_frame_new(int num); + +void +ao_lisp_frame_free(struct ao_lisp_frame *frame); + +void +ao_lisp_frame_bind(struct ao_lisp_frame *frame, int num, ao_poly atom, ao_poly val); + +int +ao_lisp_frame_add(struct ao_lisp_frame **frame, ao_poly atom, ao_poly val); + +void +ao_lisp_frame_print(ao_poly p); + +/* lambda */ +extern const struct ao_lisp_type ao_lisp_lambda_type; + +extern const char *ao_lisp_state_names[]; + +struct ao_lisp_lambda * +ao_lisp_lambda_new(ao_poly cons); + +void +ao_lisp_lambda_print(ao_poly lambda); + +ao_poly +ao_lisp_lambda(struct ao_lisp_cons *cons); + +ao_poly +ao_lisp_lexpr(struct ao_lisp_cons *cons); + +ao_poly +ao_lisp_nlambda(struct ao_lisp_cons *cons); + +ao_poly +ao_lisp_macro(struct ao_lisp_cons *cons); + +ao_poly +ao_lisp_lambda_eval(void); + +/* save */ + +ao_poly +ao_lisp_save(struct ao_lisp_cons *cons); + +ao_poly +ao_lisp_restore(struct ao_lisp_cons *cons); + +/* stack */ + +extern const struct ao_lisp_type ao_lisp_stack_type; +extern struct ao_lisp_stack	*ao_lisp_stack; +extern struct ao_lisp_stack	*ao_lisp_stack_free_list; + +void +ao_lisp_stack_reset(struct ao_lisp_stack *stack); + +int +ao_lisp_stack_push(void); + +void +ao_lisp_stack_pop(void); + +void +ao_lisp_stack_clear(void); + +void +ao_lisp_stack_print(ao_poly stack); + +ao_poly +ao_lisp_stack_eval(void); + +ao_poly +ao_lisp_call_cc(struct ao_lisp_cons *cons); + +/* error */ + +void +ao_lisp_error_poly(char *name, ao_poly poly, ao_poly last); + +void +ao_lisp_error_frame(int indent, char *name, struct ao_lisp_frame *frame); + +ao_poly +ao_lisp_error(int error, char *format, ...); + +/* debugging macros */ + +#if DBG_EVAL +#define DBG_CODE	1 +int ao_lisp_stack_depth; +#define DBG_DO(a)	a +#define DBG_INDENT()	do { int _s; for(_s = 0; _s < ao_lisp_stack_depth; _s++) printf("  "); } while(0) +#define DBG_IN()	(++ao_lisp_stack_depth) +#define DBG_OUT()	(--ao_lisp_stack_depth) +#define DBG_RESET()	(ao_lisp_stack_depth = 0) +#define DBG(...) 	printf(__VA_ARGS__) +#define DBGI(...)	do { DBG("%4d: ", __LINE__); DBG_INDENT(); DBG(__VA_ARGS__); } while (0) +#define DBG_CONS(a)	ao_lisp_cons_print(ao_lisp_cons_poly(a)) +#define DBG_POLY(a)	ao_lisp_poly_print(a) +#define OFFSET(a)	((a) ? (int) ((uint8_t *) a - ao_lisp_pool) : -1) +#define DBG_STACK()	ao_lisp_stack_print(ao_lisp_stack_poly(ao_lisp_stack)) +static inline void +ao_lisp_frames_dump(void) +{ +	struct ao_lisp_stack *s; +	DBGI(".. current frame: "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); +	for (s = ao_lisp_stack; s; s = ao_lisp_poly_stack(s->prev)) { +		DBGI(".. stack frame: "); DBG_POLY(s->frame); DBG("\n"); +	} +} +#define DBG_FRAMES()	ao_lisp_frames_dump() +#else +#define DBG_DO(a) +#define DBG_INDENT() +#define DBG_IN() +#define DBG_OUT() +#define DBG(...) +#define DBGI(...) +#define DBG_CONS(a) +#define DBG_POLY(a) +#define DBG_RESET() +#define DBG_STACK() +#define DBG_FRAMES() +#endif + +#define DBG_MEM_START	1 + +#if DBG_MEM + +#include <assert.h> +extern int dbg_move_depth; +#define MDBG_DUMP 1 +#define MDBG_OFFSET(a)	((int) ((uint8_t *) (a) - ao_lisp_pool)) + +extern int dbg_mem; + +#define MDBG_DO(a)	a +#define MDBG_MOVE(...) do { if (dbg_mem) { int d; for (d = 0; d < dbg_move_depth; d++) printf ("  "); printf(__VA_ARGS__); } } while (0) +#define MDBG_MORE(...) do { if (dbg_mem) printf(__VA_ARGS__); } while (0) +#define MDBG_MOVE_IN()	(dbg_move_depth++) +#define MDBG_MOVE_OUT()	(assert(--dbg_move_depth >= 0)) + +#else + +#define MDBG_DO(a) +#define MDBG_MOVE(...) +#define MDBG_MORE(...) +#define MDBG_MOVE_IN() +#define MDBG_MOVE_OUT() + +#endif + +#endif /* _AO_LISP_H_ */ diff --git a/src/lisp/ao_lisp_atom.c b/src/lisp/ao_lisp_atom.c new file mode 100644 index 00000000..8c9e8ed1 --- /dev/null +++ b/src/lisp/ao_lisp_atom.c @@ -0,0 +1,165 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao_lisp.h" + +static int name_size(char *name) +{ +	return sizeof(struct ao_lisp_atom) + strlen(name) + 1; +} + +static int atom_size(void *addr) +{ +	struct ao_lisp_atom	*atom = addr; +	if (!atom) +		return 0; +	return name_size(atom->name); +} + +static void atom_mark(void *addr) +{ +	struct ao_lisp_atom	*atom = addr; + +	for (;;) { +		atom = ao_lisp_poly_atom(atom->next); +		if (!atom) +			break; +		if (ao_lisp_mark_memory(&ao_lisp_atom_type, atom)) +			break; +	} +} + +static void atom_move(void *addr) +{ +	struct ao_lisp_atom	*atom = addr; +	int			ret; + +	for (;;) { +		struct ao_lisp_atom *next = ao_lisp_poly_atom(atom->next); + +		if (!next) +			break; +		ret = ao_lisp_move_memory(&ao_lisp_atom_type, (void **) &next); +		if (next != ao_lisp_poly_atom(atom->next)) +			atom->next = ao_lisp_atom_poly(next); +		if (ret) +			break; +		atom = next; +	} +} + +const struct ao_lisp_type ao_lisp_atom_type = { +	.mark = atom_mark, +	.size = atom_size, +	.move = atom_move, +	.name = "atom" +}; + +struct ao_lisp_atom	*ao_lisp_atoms; + +struct ao_lisp_atom * +ao_lisp_atom_intern(char *name) +{ +	struct ao_lisp_atom	*atom; + +	for (atom = ao_lisp_atoms; atom; atom = ao_lisp_poly_atom(atom->next)) { +		if (!strcmp(atom->name, name)) +			return atom; +	} +#ifdef ao_builtin_atoms +	for (atom = ao_lisp_poly_atom(ao_builtin_atoms); atom; atom = ao_lisp_poly_atom(atom->next)) { +		if (!strcmp(atom->name, name)) +			return atom; +	} +#endif +	ao_lisp_string_stash(0, name); +	atom = ao_lisp_alloc(name_size(name)); +	name = ao_lisp_string_fetch(0); +	if (atom) { +		atom->type = AO_LISP_ATOM; +		atom->next = ao_lisp_atom_poly(ao_lisp_atoms); +		ao_lisp_atoms = atom; +		strcpy(atom->name, name); +	} +	return atom; +} + +struct ao_lisp_frame	*ao_lisp_frame_global; +struct ao_lisp_frame	*ao_lisp_frame_current; + +static void +ao_lisp_atom_init(void) +{ +	if (!ao_lisp_frame_global) +		ao_lisp_frame_global = ao_lisp_frame_new(0); +} + +ao_poly * +ao_lisp_atom_ref(struct ao_lisp_frame *frame, ao_poly atom) +{ +	ao_poly	*ref; +	ao_lisp_atom_init(); +	while (frame) { +		ref = ao_lisp_frame_ref(frame, atom); +		if (ref) +			return ref; +		frame = ao_lisp_poly_frame(frame->prev); +	} +	if (ao_lisp_frame_global) { +		ref = ao_lisp_frame_ref(ao_lisp_frame_global, atom); +		if (ref) +			return ref; +	} +	return NULL; +} + +ao_poly +ao_lisp_atom_get(ao_poly atom) +{ +	ao_poly *ref = ao_lisp_atom_ref(ao_lisp_frame_current, atom); + +	if (!ref && ao_lisp_frame_global) +		ref = ao_lisp_frame_ref(ao_lisp_frame_global, atom); +#ifdef ao_builtin_frame +	if (!ref) +		ref = ao_lisp_frame_ref(ao_lisp_poly_frame(ao_builtin_frame), atom); +#endif +	if (ref) +		return *ref; +	return ao_lisp_error(AO_LISP_UNDEFINED, "undefined atom %s", ao_lisp_poly_atom(atom)->name); +} + +ao_poly +ao_lisp_atom_set(ao_poly atom, ao_poly val) +{ +	ao_poly *ref = ao_lisp_atom_ref(ao_lisp_frame_current, atom); + +	if (!ref && ao_lisp_frame_global) +		ref = ao_lisp_frame_ref(ao_lisp_frame_global, atom); +	if (ref) +		*ref = val; +	else +		ao_lisp_frame_add(&ao_lisp_frame_global, atom, val); +	return val; +} + +void +ao_lisp_atom_print(ao_poly a) +{ +	struct ao_lisp_atom *atom = ao_lisp_poly_atom(a); +	printf("%s", atom->name); +} diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c new file mode 100644 index 00000000..902f60e2 --- /dev/null +++ b/src/lisp/ao_lisp_builtin.c @@ -0,0 +1,619 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" + +static int +builtin_size(void *addr) +{ +	(void) addr; +	return sizeof (struct ao_lisp_builtin); +} + +static void +builtin_mark(void *addr) +{ +	(void) addr; +} + +static void +builtin_move(void *addr) +{ +	(void) addr; +} + +const struct ao_lisp_type ao_lisp_builtin_type = { +	.size = builtin_size, +	.mark = builtin_mark, +	.move = builtin_move +}; + +#ifdef AO_LISP_MAKE_CONST +char *ao_lisp_builtin_name(enum ao_lisp_builtin_id b) { +	(void) b; +	return "???"; +} +char *ao_lisp_args_name(uint8_t args) { +	(void) args; +	return "???"; +} +#else +static const ao_poly builtin_names[] = { +	[builtin_eval] = _ao_lisp_atom_eval, +	[builtin_read] = _ao_lisp_atom_read, +	[builtin_lambda] = _ao_lisp_atom_lambda, +	[builtin_lexpr] = _ao_lisp_atom_lexpr, +	[builtin_nlambda] = _ao_lisp_atom_nlambda, +	[builtin_macro] = _ao_lisp_atom_macro, +	[builtin_car] = _ao_lisp_atom_car, +	[builtin_cdr] = _ao_lisp_atom_cdr, +	[builtin_cons] = _ao_lisp_atom_cons, +	[builtin_last] = _ao_lisp_atom_last, +	[builtin_length] = _ao_lisp_atom_length, +	[builtin_quote] = _ao_lisp_atom_quote, +	[builtin_set] = _ao_lisp_atom_set, +	[builtin_setq] = _ao_lisp_atom_setq, +	[builtin_cond] = _ao_lisp_atom_cond, +	[builtin_progn] = _ao_lisp_atom_progn, +	[builtin_while] = _ao_lisp_atom_while, +	[builtin_print] = _ao_lisp_atom_print, +	[builtin_patom] = _ao_lisp_atom_patom, +	[builtin_plus] = _ao_lisp_atom_2b, +	[builtin_minus] = _ao_lisp_atom_2d, +	[builtin_times] = _ao_lisp_atom_2a, +	[builtin_divide] = _ao_lisp_atom_2f, +	[builtin_mod] = _ao_lisp_atom_25, +	[builtin_equal] = _ao_lisp_atom_3d, +	[builtin_less] = _ao_lisp_atom_3c, +	[builtin_greater] = _ao_lisp_atom_3e, +	[builtin_less_equal] = _ao_lisp_atom_3c3d, +	[builtin_greater_equal] = _ao_lisp_atom_3e3d, +	[builtin_pack] = _ao_lisp_atom_pack, +	[builtin_unpack] = _ao_lisp_atom_unpack, +	[builtin_flush] = _ao_lisp_atom_flush, +	[builtin_delay] = _ao_lisp_atom_delay, +	[builtin_led] = _ao_lisp_atom_led, +	[builtin_save] = _ao_lisp_atom_save, +	[builtin_restore] = _ao_lisp_atom_restore, +	[builtin_call_cc] = _ao_lisp_atom_call2fcc, +	[builtin_collect] = _ao_lisp_atom_collect, +#if 0 +	[builtin_symbolp] = _ao_lisp_atom_symbolp, +	[builtin_listp] = _ao_lisp_atom_listp, +	[builtin_stringp] = _ao_lisp_atom_stringp, +	[builtin_numberp] = _ao_lisp_atom_numberp, +#endif +}; + +static char * +ao_lisp_builtin_name(enum ao_lisp_builtin_id b) { +	if (b < _builtin_last) +		return ao_lisp_poly_atom(builtin_names[b])->name; +	return "???"; +} + +static const ao_poly ao_lisp_args_atoms[] = { +	[AO_LISP_FUNC_LAMBDA] = _ao_lisp_atom_lambda, +	[AO_LISP_FUNC_LEXPR] = _ao_lisp_atom_lexpr, +	[AO_LISP_FUNC_NLAMBDA] = _ao_lisp_atom_nlambda, +	[AO_LISP_FUNC_MACRO] = _ao_lisp_atom_macro, +}; + +char * +ao_lisp_args_name(uint8_t args) +{ +	args &= AO_LISP_FUNC_MASK; +	if (args < sizeof ao_lisp_args_atoms / sizeof ao_lisp_args_atoms[0]) +		return ao_lisp_poly_atom(ao_lisp_args_atoms[args])->name; +	return "(unknown)"; +} +#endif + +void +ao_lisp_builtin_print(ao_poly b) +{ +	struct ao_lisp_builtin *builtin = ao_lisp_poly_builtin(b); +	printf("%s", ao_lisp_builtin_name(builtin->func)); +} + +ao_poly +ao_lisp_check_argc(ao_poly name, struct ao_lisp_cons *cons, int min, int max) +{ +	int	argc = 0; + +	while (cons && argc <= max) { +		argc++; +		cons = ao_lisp_poly_cons(cons->cdr); +	} +	if (argc < min || argc > max) +		return ao_lisp_error(AO_LISP_INVALID, "%s: invalid arg count", ao_lisp_poly_atom(name)->name); +	return _ao_lisp_atom_t; +} + +ao_poly +ao_lisp_arg(struct ao_lisp_cons *cons, int argc) +{ +	if (!cons) +		return AO_LISP_NIL; +	while (argc--) { +		if (!cons) +			return AO_LISP_NIL; +		cons = ao_lisp_poly_cons(cons->cdr); +	} +	return cons->car; +} + +ao_poly +ao_lisp_check_argt(ao_poly name, struct ao_lisp_cons *cons, int argc, int type, int nil_ok) +{ +	ao_poly car = ao_lisp_arg(cons, argc); + +	if ((!car && !nil_ok) || ao_lisp_poly_type(car) != type) +		return ao_lisp_error(AO_LISP_INVALID, "%s: invalid type for arg %d", ao_lisp_poly_atom(name)->name, argc); +	return _ao_lisp_atom_t; +} + +ao_poly +ao_lisp_car(struct ao_lisp_cons *cons) +{ +	if (!ao_lisp_check_argc(_ao_lisp_atom_car, cons, 1, 1)) +		return AO_LISP_NIL; +	if (!ao_lisp_check_argt(_ao_lisp_atom_car, cons, 0, AO_LISP_CONS, 0)) +		return AO_LISP_NIL; +	return ao_lisp_poly_cons(cons->car)->car; +} + +ao_poly +ao_lisp_cdr(struct ao_lisp_cons *cons) +{ +	if (!ao_lisp_check_argc(_ao_lisp_atom_cdr, cons, 1, 1)) +		return AO_LISP_NIL; +	if (!ao_lisp_check_argt(_ao_lisp_atom_cdr, cons, 0, AO_LISP_CONS, 0)) +		return AO_LISP_NIL; +	return ao_lisp_poly_cons(cons->car)->cdr; +} + +ao_poly +ao_lisp_cons(struct ao_lisp_cons *cons) +{ +	ao_poly	car, cdr; +	if(!ao_lisp_check_argc(_ao_lisp_atom_cons, cons, 2, 2)) +		return AO_LISP_NIL; +	if (!ao_lisp_check_argt(_ao_lisp_atom_cons, cons, 1, AO_LISP_CONS, 1)) +		return AO_LISP_NIL; +	car = ao_lisp_arg(cons, 0); +	cdr = ao_lisp_arg(cons, 1); +	return ao_lisp_cons_poly(ao_lisp_cons_cons(car, ao_lisp_poly_cons(cdr))); +} + +ao_poly +ao_lisp_last(struct ao_lisp_cons *cons) +{ +	ao_poly	l; +	if (!ao_lisp_check_argc(_ao_lisp_atom_last, cons, 1, 1)) +		return AO_LISP_NIL; +	if (!ao_lisp_check_argt(_ao_lisp_atom_last, cons, 0, AO_LISP_CONS, 1)) +		return AO_LISP_NIL; +	l = ao_lisp_arg(cons, 0); +	while (l) { +		struct ao_lisp_cons *list = ao_lisp_poly_cons(l); +		if (!list->cdr) +			return list->car; +		l = list->cdr; +	} +	return AO_LISP_NIL; +} + +ao_poly +ao_lisp_length(struct ao_lisp_cons *cons) +{ +	if (!ao_lisp_check_argc(_ao_lisp_atom_length, cons, 1, 1)) +		return AO_LISP_NIL; +	if (!ao_lisp_check_argt(_ao_lisp_atom_length, cons, 0, AO_LISP_CONS, 1)) +		return AO_LISP_NIL; +	return ao_lisp_int_poly(ao_lisp_cons_length(ao_lisp_poly_cons(ao_lisp_arg(cons, 0)))); +} + +ao_poly +ao_lisp_quote(struct ao_lisp_cons *cons) +{ +	if (!ao_lisp_check_argc(_ao_lisp_atom_quote, cons, 1, 1)) +		return AO_LISP_NIL; +	return ao_lisp_arg(cons, 0); +} + +ao_poly +ao_lisp_set(struct ao_lisp_cons *cons) +{ +	if (!ao_lisp_check_argc(_ao_lisp_atom_set, cons, 2, 2)) +		return AO_LISP_NIL; +	if (!ao_lisp_check_argt(_ao_lisp_atom_set, cons, 0, AO_LISP_ATOM, 0)) +		return AO_LISP_NIL; + +	return ao_lisp_atom_set(ao_lisp_arg(cons, 0), ao_lisp_arg(cons, 1)); +} + +ao_poly +ao_lisp_setq(struct ao_lisp_cons *cons) +{ +	struct ao_lisp_cons	*expand = 0; +	if (!ao_lisp_check_argc(_ao_lisp_atom_setq, cons, 2, 2)) +		return AO_LISP_NIL; +	expand = ao_lisp_cons_cons(_ao_lisp_atom_set, +				   ao_lisp_cons_cons(ao_lisp_cons_poly(ao_lisp_cons_cons(_ao_lisp_atom_quote, +								       ao_lisp_cons_cons(cons->car, NULL))), +						     ao_lisp_poly_cons(cons->cdr))); +	return ao_lisp_cons_poly(expand); +} + +ao_poly +ao_lisp_cond(struct ao_lisp_cons *cons) +{ +	ao_lisp_set_cond(cons); +	return AO_LISP_NIL; +} + +ao_poly +ao_lisp_progn(struct ao_lisp_cons *cons) +{ +	ao_lisp_stack->state = eval_progn; +	ao_lisp_stack->sexprs = ao_lisp_cons_poly(cons); +	return AO_LISP_NIL; +} + +ao_poly +ao_lisp_while(struct ao_lisp_cons *cons) +{ +	ao_lisp_stack->state = eval_while; +	ao_lisp_stack->sexprs = ao_lisp_cons_poly(cons); +	return AO_LISP_NIL; +} + +ao_poly +ao_lisp_print(struct ao_lisp_cons *cons) +{ +	ao_poly	val = AO_LISP_NIL; +	while (cons) { +		val = cons->car; +		ao_lisp_poly_print(val); +		cons = ao_lisp_poly_cons(cons->cdr); +		if (cons) +			printf(" "); +	} +	printf("\n"); +	return val; +} + +ao_poly +ao_lisp_patom(struct ao_lisp_cons *cons) +{ +	ao_poly	val = AO_LISP_NIL; +	while (cons) { +		val = cons->car; +		ao_lisp_poly_patom(val); +		cons = ao_lisp_poly_cons(cons->cdr); +	} +	return val; +} + +ao_poly +ao_lisp_math(struct ao_lisp_cons *cons, enum ao_lisp_builtin_id op) +{ +	ao_poly	ret = AO_LISP_NIL; + +	while (cons) { +		ao_poly		car = cons->car; +		uint8_t		rt = ao_lisp_poly_type(ret); +		uint8_t		ct = ao_lisp_poly_type(car); + +		cons = ao_lisp_poly_cons(cons->cdr); + +		if (rt == AO_LISP_NIL) +			ret = car; + +		else if (rt == AO_LISP_INT && ct == AO_LISP_INT) { +			int	r = ao_lisp_poly_int(ret); +			int	c = ao_lisp_poly_int(car); + +			switch(op) { +			case builtin_plus: +				r += c; +				break; +			case builtin_minus: +				r -= c; +				break; +			case builtin_times: +				r *= c; +				break; +			case builtin_divide: +				if (c == 0) +					return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "divide by zero"); +				r /= c; +				break; +			case builtin_mod: +				if (c == 0) +					return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "mod by zero"); +				r %= c; +				break; +			default: +				break; +			} +			ret = ao_lisp_int_poly(r); +		} + +		else if (rt == AO_LISP_STRING && ct == AO_LISP_STRING && op == builtin_plus) +			ret = ao_lisp_string_poly(ao_lisp_string_cat(ao_lisp_poly_string(ret), +								     ao_lisp_poly_string(car))); +		else +			return ao_lisp_error(AO_LISP_INVALID, "invalid args"); +	} +	return ret; +} + +ao_poly +ao_lisp_plus(struct ao_lisp_cons *cons) +{ +	return ao_lisp_math(cons, builtin_plus); +} + +ao_poly +ao_lisp_minus(struct ao_lisp_cons *cons) +{ +	return ao_lisp_math(cons, builtin_minus); +} + +ao_poly +ao_lisp_times(struct ao_lisp_cons *cons) +{ +	return ao_lisp_math(cons, builtin_times); +} + +ao_poly +ao_lisp_divide(struct ao_lisp_cons *cons) +{ +	return ao_lisp_math(cons, builtin_divide); +} + +ao_poly +ao_lisp_mod(struct ao_lisp_cons *cons) +{ +	return ao_lisp_math(cons, builtin_mod); +} + +ao_poly +ao_lisp_compare(struct ao_lisp_cons *cons, enum ao_lisp_builtin_id op) +{ +	ao_poly	left; + +	if (!cons) +		return _ao_lisp_atom_t; + +	left = cons->car; +	cons = ao_lisp_poly_cons(cons->cdr); +	while (cons) { +		ao_poly	right = cons->car; + +		if (op == builtin_equal) { +			if (left != right) +				return AO_LISP_NIL; +		} else { +			uint8_t	lt = ao_lisp_poly_type(left); +			uint8_t	rt = ao_lisp_poly_type(right); +			if (lt == AO_LISP_INT && rt == AO_LISP_INT) { +				int l = ao_lisp_poly_int(left); +				int r = ao_lisp_poly_int(right); + +				switch (op) { +				case builtin_less: +					if (!(l < r)) +						return AO_LISP_NIL; +					break; +				case builtin_greater: +					if (!(l > r)) +						return AO_LISP_NIL; +					break; +				case builtin_less_equal: +					if (!(l <= r)) +						return AO_LISP_NIL; +					break; +				case builtin_greater_equal: +					if (!(l >= r)) +						return AO_LISP_NIL; +					break; +				default: +					break; +				} +			} else if (lt == AO_LISP_STRING && rt == AO_LISP_STRING) { +				int c = strcmp(ao_lisp_poly_string(left), +					       ao_lisp_poly_string(right)); +				switch (op) { +				case builtin_less: +					if (!(c < 0)) +						return AO_LISP_NIL; +					break; +				case builtin_greater: +					if (!(c > 0)) +						return AO_LISP_NIL; +					break; +				case builtin_less_equal: +					if (!(c <= 0)) +						return AO_LISP_NIL; +					break; +				case builtin_greater_equal: +					if (!(c >= 0)) +						return AO_LISP_NIL; +					break; +				default: +					break; +				} +			} +		} +		left = right; +		cons = ao_lisp_poly_cons(cons->cdr); +	} +	return _ao_lisp_atom_t; +} + +ao_poly +ao_lisp_equal(struct ao_lisp_cons *cons) +{ +	return ao_lisp_compare(cons, builtin_equal); +} + +ao_poly +ao_lisp_less(struct ao_lisp_cons *cons) +{ +	return ao_lisp_compare(cons, builtin_less); +} + +ao_poly +ao_lisp_greater(struct ao_lisp_cons *cons) +{ +	return ao_lisp_compare(cons, builtin_greater); +} + +ao_poly +ao_lisp_less_equal(struct ao_lisp_cons *cons) +{ +	return ao_lisp_compare(cons, builtin_less_equal); +} + +ao_poly +ao_lisp_greater_equal(struct ao_lisp_cons *cons) +{ +	return ao_lisp_compare(cons, builtin_greater_equal); +} + +ao_poly +ao_lisp_pack(struct ao_lisp_cons *cons) +{ +	if (!ao_lisp_check_argc(_ao_lisp_atom_pack, cons, 1, 1)) +		return AO_LISP_NIL; +	if (!ao_lisp_check_argt(_ao_lisp_atom_pack, cons, 0, AO_LISP_CONS, 1)) +		return AO_LISP_NIL; +	return ao_lisp_string_pack(ao_lisp_poly_cons(ao_lisp_arg(cons, 0))); +} + +ao_poly +ao_lisp_unpack(struct ao_lisp_cons *cons) +{ +	if (!ao_lisp_check_argc(_ao_lisp_atom_unpack, cons, 1, 1)) +		return AO_LISP_NIL; +	if (!ao_lisp_check_argt(_ao_lisp_atom_unpack, cons, 0, AO_LISP_STRING, 0)) +		return AO_LISP_NIL; +	return ao_lisp_string_unpack(ao_lisp_poly_string(ao_lisp_arg(cons, 0))); +} + +ao_poly +ao_lisp_flush(struct ao_lisp_cons *cons) +{ +	if (!ao_lisp_check_argc(_ao_lisp_atom_flush, cons, 0, 0)) +		return AO_LISP_NIL; +	ao_lisp_os_flush(); +	return _ao_lisp_atom_t; +} + +ao_poly +ao_lisp_led(struct ao_lisp_cons *cons) +{ +	ao_poly led; +	if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1)) +		return AO_LISP_NIL; +	if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_INT, 0)) +		return AO_LISP_NIL; +	led = ao_lisp_arg(cons, 0); +	ao_lisp_os_led(ao_lisp_poly_int(led)); +	return led; +} + +ao_poly +ao_lisp_delay(struct ao_lisp_cons *cons) +{ +	ao_poly delay; +	if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1)) +		return AO_LISP_NIL; +	if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_INT, 0)) +		return AO_LISP_NIL; +	delay = ao_lisp_arg(cons, 0); +	ao_lisp_os_delay(ao_lisp_poly_int(delay)); +	return delay; +} + +ao_poly +ao_lisp_do_eval(struct ao_lisp_cons *cons) +{ +	if (!ao_lisp_check_argc(_ao_lisp_atom_eval, cons, 1, 1)) +		return AO_LISP_NIL; +	ao_lisp_stack->state = eval_sexpr; +	return cons->car; +} + +ao_poly +ao_lisp_do_read(struct ao_lisp_cons *cons) +{ +	if (!ao_lisp_check_argc(_ao_lisp_atom_read, cons, 0, 0)) +		return AO_LISP_NIL; +	return ao_lisp_read(); +} + +ao_poly +ao_lisp_do_collect(struct ao_lisp_cons *cons) +{ +	int	free; +	(void) cons; +	free = ao_lisp_collect(AO_LISP_COLLECT_FULL); +	return ao_lisp_int_poly(free); +} + +const ao_lisp_func_t ao_lisp_builtins[] = { +	[builtin_eval] = ao_lisp_do_eval, +	[builtin_read] = ao_lisp_do_read, +	[builtin_lambda] = ao_lisp_lambda, +	[builtin_lexpr] = ao_lisp_lexpr, +	[builtin_nlambda] = ao_lisp_nlambda, +	[builtin_macro] = ao_lisp_macro, +	[builtin_car] = ao_lisp_car, +	[builtin_cdr] = ao_lisp_cdr, +	[builtin_cons] = ao_lisp_cons, +	[builtin_last] = ao_lisp_last, +	[builtin_length] = ao_lisp_length, +	[builtin_quote] = ao_lisp_quote, +	[builtin_set] = ao_lisp_set, +	[builtin_setq] = ao_lisp_setq, +	[builtin_cond] = ao_lisp_cond, +	[builtin_progn] = ao_lisp_progn, +	[builtin_while] = ao_lisp_while, +	[builtin_print] = ao_lisp_print, +	[builtin_patom] = ao_lisp_patom, +	[builtin_plus] = ao_lisp_plus, +	[builtin_minus] = ao_lisp_minus, +	[builtin_times] = ao_lisp_times, +	[builtin_divide] = ao_lisp_divide, +	[builtin_mod] = ao_lisp_mod, +	[builtin_equal] = ao_lisp_equal, +	[builtin_less] = ao_lisp_less, +	[builtin_greater] = ao_lisp_greater, +	[builtin_less_equal] = ao_lisp_less_equal, +	[builtin_greater_equal] = ao_lisp_greater_equal, +	[builtin_pack] = ao_lisp_pack, +	[builtin_unpack] = ao_lisp_unpack, +	[builtin_flush] = ao_lisp_flush, +	[builtin_led] = ao_lisp_led, +	[builtin_delay] = ao_lisp_delay, +	[builtin_save] = ao_lisp_save, +	[builtin_restore] = ao_lisp_restore, +	[builtin_call_cc] = ao_lisp_call_cc, +	[builtin_collect] = ao_lisp_do_collect, +}; + diff --git a/src/lisp/ao_lisp_cons.c b/src/lisp/ao_lisp_cons.c new file mode 100644 index 00000000..d2b60c9a --- /dev/null +++ b/src/lisp/ao_lisp_cons.c @@ -0,0 +1,143 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" + +static void cons_mark(void *addr) +{ +	struct ao_lisp_cons	*cons = addr; + +	for (;;) { +		ao_lisp_poly_mark(cons->car, 1); +		cons = ao_lisp_poly_cons(cons->cdr); +		if (!cons) +			break; +		if (ao_lisp_mark_memory(&ao_lisp_cons_type, cons)) +			break; +	} +} + +static int cons_size(void *addr) +{ +	(void) addr; +	return sizeof (struct ao_lisp_cons); +} + +static void cons_move(void *addr) +{ +	struct ao_lisp_cons	*cons = addr; + +	if (!cons) +		return; + +	for (;;) { +		struct ao_lisp_cons	*cdr; +		int			ret; + +		MDBG_MOVE("cons_move start %d (%d, %d)\n", +			  MDBG_OFFSET(cons), MDBG_OFFSET(ao_lisp_ref(cons->car)), MDBG_OFFSET(ao_lisp_ref(cons->cdr))); +		(void) ao_lisp_poly_move(&cons->car, 1); +		cdr = ao_lisp_poly_cons(cons->cdr); +		if (!cdr) +			break; +		ret = ao_lisp_move_memory(&ao_lisp_cons_type, (void **) &cdr); +		if (cdr != ao_lisp_poly_cons(cons->cdr)) +			cons->cdr = ao_lisp_cons_poly(cdr); +		MDBG_MOVE("cons_move end %d (%d, %d)\n", +			  MDBG_OFFSET(cons), MDBG_OFFSET(ao_lisp_ref(cons->car)), MDBG_OFFSET(ao_lisp_ref(cons->cdr))); +		if (ret) +			break; +		cons = cdr; +	} +} + +const struct ao_lisp_type ao_lisp_cons_type = { +	.mark = cons_mark, +	.size = cons_size, +	.move = cons_move, +	.name = "cons", +}; + +struct ao_lisp_cons *ao_lisp_cons_free_list; + +struct ao_lisp_cons * +ao_lisp_cons_cons(ao_poly car, struct ao_lisp_cons *cdr) +{ +	struct ao_lisp_cons	*cons; + +	if (ao_lisp_cons_free_list) { +		cons = ao_lisp_cons_free_list; +		ao_lisp_cons_free_list = ao_lisp_poly_cons(cons->cdr); +	} else { +		ao_lisp_poly_stash(0, car); +		ao_lisp_cons_stash(0, cdr); +		cons = ao_lisp_alloc(sizeof (struct ao_lisp_cons)); +		car = ao_lisp_poly_fetch(0); +		cdr = ao_lisp_cons_fetch(0); +		if (!cons) +			return NULL; +	} +	cons->car = car; +	cons->cdr = ao_lisp_cons_poly(cdr); +	return cons; +} + +void +ao_lisp_cons_free(struct ao_lisp_cons *cons) +{ +	while (cons) { +		ao_poly cdr = cons->cdr; +		cons->cdr = ao_lisp_cons_poly(ao_lisp_cons_free_list); +		ao_lisp_cons_free_list = cons; +		cons = ao_lisp_poly_cons(cdr); +	} +} + +void +ao_lisp_cons_print(ao_poly c) +{ +	struct ao_lisp_cons *cons = ao_lisp_poly_cons(c); +	int	first = 1; +	printf("("); +	while (cons) { +		if (!first) +			printf(" "); +		ao_lisp_poly_print(cons->car); +		cons = ao_lisp_poly_cons(cons->cdr); +		first = 0; +	} +	printf(")"); +} + +void +ao_lisp_cons_patom(ao_poly c) +{ +	struct ao_lisp_cons *cons = ao_lisp_poly_cons(c); + +	while (cons) { +		ao_lisp_poly_patom(cons->car); +		cons = ao_lisp_poly_cons(cons->cdr); +	} +} + +int +ao_lisp_cons_length(struct ao_lisp_cons *cons) +{ +	int	len = 0; +	while (cons) { +		len++; +		cons = ao_lisp_poly_cons(cons->cdr); +	} +	return len; +} diff --git a/src/lisp/ao_lisp_const.lisp b/src/lisp/ao_lisp_const.lisp new file mode 100644 index 00000000..3c8fd21b --- /dev/null +++ b/src/lisp/ao_lisp_const.lisp @@ -0,0 +1,184 @@ +; +; Copyright © 2016 Keith Packard <keithp@keithp.com> +; +; This program is free software; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, either version 2 of the License, or +; (at your option) any later version. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +; General Public License for more details. +; +; Lisp code placed in ROM + +					; return a list containing all of the arguments + +(set (quote list) (lexpr (l) l)) + +					; +					; Define a variable without returning the value +					; Useful when defining functions to avoid +					; having lots of output generated +					; + +(setq def (macro (name val rest) +		 (list +		  'progn +		  (list +		   'set +		   (list 'quote name) +		   val) +		  (list 'quote name) +		  ) +		 ) +      ) + +					; +					; A slightly more convenient form +					; for defining lambdas. +					; +					; (defun <name> (<params>) s-exprs) +					; + +(def defun (macro (name args exprs) +		  (list +		   def +		   name +		   (cons 'lambda (cons args exprs)) +		   ) +		  ) +     ) + +					; basic list accessors + + +(defun cadr (l) (car (cdr l))) + +(defun caddr (l) (car (cdr (cdr l)))) + +(defun nth (list n) +  (cond ((= n 0) (car list)) +	((nth (cdr list) (1- n))) +	) +  ) + +					; simple math operators + +(defun 1+ (x) (+ x 1)) +(defun 1- (x) (- x 1)) + +					; define a set of local +					; variables and then evaluate +					; a list of sexprs +					; +					; (let (var-defines) sexprs) +					; +					; where var-defines are either +					; +					; (name value) +					; +					; or +					; +					; (name) +					; +					; e.g. +					; +					; (let ((x 1) (y)) (setq y (+ x 1)) y) + +(def let (macro (vars exprs) +		((lambda (make-names make-exprs make-nils) + +					; +					; make the list of names in the let +					; + +		   (setq make-names (lambda (vars) +				      (cond (vars +					     (cons (car (car vars)) +						   (make-names (cdr vars)))) +					    ) +				      ) +			 ) + +					; the set of expressions is +					; the list of set expressions +					; pre-pended to the +					; expressions to evaluate + +		   (setq make-exprs (lambda (vars exprs) +				      (cond (vars (cons +						   (list set +							 (list quote +							       (car (car vars)) +							       ) +							 (cadr (car vars)) +							 ) +						   (make-exprs (cdr vars) exprs) +						   ) +						  ) +					    (exprs) +					    ) +				      ) +			 ) + +					; the parameters to the lambda is a list +					; of nils of the right length + +		   (setq make-nils (lambda (vars) +				     (cond (vars (cons nil (make-nils (cdr vars)))) +					   ) +				     ) +			 ) +					; prepend the set operations +					; to the expressions + +		   (setq exprs (make-exprs vars exprs)) + +					; build the lambda. + +		   (cons (cons 'lambda (cons (make-names vars) exprs)) +			 (make-nils vars) +			 ) +		   ) +		 () +		 () +		 () +		 ) +		) +     ) + +					; boolean operators + +(def or (lexpr (l) +	       (let ((ret nil)) +		 (while l +		   (cond ((setq ret (car l)) +			  (setq l nil)) +			 ((setq l (cdr l))))) +		 ret +		 ) +	       ) +     ) + +					; execute to resolve macros + +(or nil t) + +(def and (lexpr (l) +	       (let ((ret t)) +		 (while l +		   (cond ((setq ret (car l)) +			  (setq l (cdr l))) +			 ((setq ret (setq l nil))) +			 ) +		   ) +		 ret +		 ) +	       ) +     ) + +					; execute to resolve macros + +(and t nil) diff --git a/src/lisp/ao_lisp_error.c b/src/lisp/ao_lisp_error.c new file mode 100644 index 00000000..54a9be10 --- /dev/null +++ b/src/lisp/ao_lisp_error.c @@ -0,0 +1,102 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" +#include <stdarg.h> + +void +ao_lisp_error_poly(char *name, ao_poly poly, ao_poly last) +{ +	int first = 1; +	printf("\t\t%s(", name); +	if (ao_lisp_poly_type(poly) == AO_LISP_CONS) { +		if (poly) { +			while (poly) { +				struct ao_lisp_cons *cons = ao_lisp_poly_cons(poly); +				if (!first) +					printf("\t\t         "); +				else +					first = 0; +				ao_lisp_poly_print(cons->car); +				printf("\n"); +				if (poly == last) +					break; +				poly = cons->cdr; +			} +			printf("\t\t         )\n"); +		} else +			printf(")\n"); +	} else { +		ao_lisp_poly_print(poly); +		printf("\n"); +	} +} + +static void tabs(int indent) +{ +	while (indent--) +		printf("\t"); +} + +void +ao_lisp_error_frame(int indent, char *name, struct ao_lisp_frame *frame) +{ +	int			f; + +	tabs(indent); +	printf ("%s{", name); +	if (frame) { +		if (frame->type & AO_LISP_FRAME_PRINT) +			printf("recurse..."); +		else { +			frame->type |= AO_LISP_FRAME_PRINT; +			for (f = 0; f < frame->num; f++) { +				if (f != 0) { +					tabs(indent); +					printf("         "); +				} +				ao_lisp_poly_print(frame->vals[f].atom); +				printf(" = "); +				ao_lisp_poly_print(frame->vals[f].val); +				printf("\n"); +			} +			if (frame->prev) +				ao_lisp_error_frame(indent + 1, "prev:   ", ao_lisp_poly_frame(frame->prev)); +			frame->type &= ~AO_LISP_FRAME_PRINT; +		} +		tabs(indent); +		printf("        }\n"); +	} else +		printf ("}\n"); +} + + +ao_poly +ao_lisp_error(int error, char *format, ...) +{ +	va_list	args; + +	ao_lisp_exception |= error; +	va_start(args, format); +	vprintf(format, args); +	va_end(args); +	printf("\n"); +	printf("Value: "); ao_lisp_poly_print(ao_lisp_v); printf("\n"); +	printf("Stack:\n"); +	ao_lisp_stack_print(ao_lisp_stack_poly(ao_lisp_stack)); +	printf("Globals:\n\t"); +	ao_lisp_frame_print(ao_lisp_frame_poly(ao_lisp_frame_global)); +	printf("\n"); +	return AO_LISP_NIL; +} diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c new file mode 100644 index 00000000..3be7c9c4 --- /dev/null +++ b/src/lisp/ao_lisp_eval.c @@ -0,0 +1,531 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" +#include <assert.h> + +struct ao_lisp_stack		*ao_lisp_stack; +ao_poly				ao_lisp_v; + +ao_poly +ao_lisp_set_cond(struct ao_lisp_cons *c) +{ +	ao_lisp_stack->state = eval_cond; +	ao_lisp_stack->sexprs = ao_lisp_cons_poly(c); +	return AO_LISP_NIL; +} + +static int +func_type(ao_poly func) +{ +	if (func == AO_LISP_NIL) +		return ao_lisp_error(AO_LISP_INVALID, "func is nil"); +	switch (ao_lisp_poly_type(func)) { +	case AO_LISP_BUILTIN: +		return ao_lisp_poly_builtin(func)->args & AO_LISP_FUNC_MASK; +	case AO_LISP_LAMBDA: +		return ao_lisp_poly_lambda(func)->args; +	case AO_LISP_STACK: +		return AO_LISP_FUNC_LAMBDA; +	default: +		ao_lisp_error(AO_LISP_INVALID, "not a func"); +		return -1; +	} +} + +/* + * Flattened eval to avoid stack issues + */ + +/* + * Evaluate an s-expression + * + * For a list, evaluate all of the elements and + * then execute the resulting function call. + * + * Each element of the list is evaluated in + * a clean stack context. + * + * The current stack state is set to 'formal' so that + * when the evaluation is complete, the value + * will get appended to the values list. + * + * For other types, compute the value directly. + */ + +static int +ao_lisp_eval_sexpr(void) +{ +	DBGI("sexpr: "); DBG_POLY(ao_lisp_v); DBG("\n"); +	switch (ao_lisp_poly_type(ao_lisp_v)) { +	case AO_LISP_CONS: +		if (ao_lisp_v == AO_LISP_NIL) { +			if (!ao_lisp_stack->values) { +				/* +				 * empty list evaluates to empty list +				 */ +				ao_lisp_v = AO_LISP_NIL; +				ao_lisp_stack->state = eval_val; +			} else { +				/* +				 * done with arguments, go execute it +				 */ +				ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->values)->car; +				ao_lisp_stack->state = eval_exec; +			} +		} else { +			if (!ao_lisp_stack->values) +				ao_lisp_stack->list = ao_lisp_v; +			/* +			 * Evaluate another argument and then switch +			 * to 'formal' to add the value to the values +			 * list +			 */ +			ao_lisp_stack->sexprs = ao_lisp_v; +			ao_lisp_stack->state = eval_formal; +			if (!ao_lisp_stack_push()) +				return 0; +			/* +			 * push will reset the state to 'sexpr', which +			 * will evaluate the expression +			 */ +			ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car; +		} +		break; +	case AO_LISP_ATOM: +		DBGI("..frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); +		ao_lisp_v = ao_lisp_atom_get(ao_lisp_v); +		/* fall through */ +	case AO_LISP_INT: +	case AO_LISP_STRING: +	case AO_LISP_BUILTIN: +	case AO_LISP_LAMBDA: +		ao_lisp_stack->state = eval_val; +		break; +	} +	DBGI(".. result "); DBG_POLY(ao_lisp_v); DBG("\n"); +	return 1; +} + +/* + * A value has been computed. + * + * If the value was computed from a macro, + * then we want to reset the current context + * to evaluate the macro result again. + * + * If not a macro, then pop the stack. + * If the stack is empty, we're done. + * Otherwise, the stack will contain + * the next state. + */ + +static int +ao_lisp_eval_val(void) +{ +	DBGI("val: "); DBG_POLY(ao_lisp_v); DBG("\n"); +	/* +	 * Value computed, pop the stack +	 * to figure out what to do with the value +	 */ +	ao_lisp_stack_pop(); +	DBGI("..state %d\n", ao_lisp_stack ? ao_lisp_stack->state : -1); +	return 1; +} + +/* + * A formal has been computed. + * + * If this is the first formal, then check to see if we've got a + * lamda/lexpr or macro/nlambda. + * + * For lambda/lexpr, go compute another formal.  This will terminate + * when the sexpr state sees nil. + * + * For macro/nlambda, we're done, so move the sexprs into the values + * and go execute it. + * + * Macros have an additional step of saving a stack frame holding the + * macro value execution context, which then gets the result of the + * macro to run + */ + +static int +ao_lisp_eval_formal(void) +{ +	ao_poly			formal; +	struct ao_lisp_stack	*prev; + +	DBGI("formal: "); DBG_POLY(ao_lisp_v); DBG("\n"); + +	/* Check what kind of function we've got */ +	if (!ao_lisp_stack->values) { +		switch (func_type(ao_lisp_v)) { +		case AO_LISP_FUNC_LAMBDA: +		case AO_LISP_FUNC_LEXPR: +			DBGI(".. lambda or lexpr\n"); +			break; +		case AO_LISP_FUNC_MACRO: +			/* Evaluate the result once more */ +			ao_lisp_stack->state = eval_macro; +			if (!ao_lisp_stack_push()) +				return 0; + +			/* After the function returns, take that +			 * value and re-evaluate it +			 */ +			prev = ao_lisp_poly_stack(ao_lisp_stack->prev); +			ao_lisp_stack->sexprs = prev->sexprs; + +			DBGI(".. start macro\n"); +			DBGI(".. sexprs       "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); +			DBGI(".. values       "); DBG_POLY(ao_lisp_stack->values); DBG("\n"); +			DBG_FRAMES(); + +			/* fall through ... */ +		case AO_LISP_FUNC_NLAMBDA: +			DBGI(".. nlambda or macro\n"); + +			/* use the raw sexprs as values */ +			ao_lisp_stack->values = ao_lisp_stack->sexprs; +			ao_lisp_stack->values_tail = AO_LISP_NIL; +			ao_lisp_stack->state = eval_exec; + +			/* ready to execute now */ +			return 1; +		case -1: +			return 0; +		} +	} + +	/* Append formal to list of values */ +	formal = ao_lisp_cons_poly(ao_lisp_cons_cons(ao_lisp_v, NULL)); +	if (!formal) +		return 0; + +	if (ao_lisp_stack->values_tail) +		ao_lisp_poly_cons(ao_lisp_stack->values_tail)->cdr = formal; +	else +		ao_lisp_stack->values = formal; +	ao_lisp_stack->values_tail = formal; + +	DBGI(".. values "); DBG_POLY(ao_lisp_stack->values); DBG("\n"); + +	/* +	 * Step to the next argument, if this is last, then +	 * 'sexpr' will end up switching to 'exec' +	 */ +	ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr; + +	ao_lisp_stack->state = eval_sexpr; + +	DBGI(".. "); DBG_POLY(ao_lisp_v); DBG("\n"); +	return 1; +} + +/* + * Start executing a function call + * + * Most builtins are easy, just call the function. + * 'cond' is magic; it sticks the list of clauses + * in 'sexprs' and switches to 'cond' state. That + * bit of magic is done in ao_lisp_set_cond. + * + * Lambdas build a new frame to hold the locals and + * then re-use the current stack context to evaluate + * the s-expression from the lambda. + */ + +static int +ao_lisp_eval_exec(void) +{ +	ao_poly v; +	struct ao_lisp_builtin	*builtin; + +	DBGI("exec: "); DBG_POLY(ao_lisp_v); DBG(" values "); DBG_POLY(ao_lisp_stack->values); DBG ("\n"); +	ao_lisp_stack->sexprs = AO_LISP_NIL; +	switch (ao_lisp_poly_type(ao_lisp_v)) { +	case AO_LISP_BUILTIN: +		ao_lisp_stack->state = eval_val; +		builtin = ao_lisp_poly_builtin(ao_lisp_v); +		v = ao_lisp_func(builtin) ( +			ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->values)->cdr)); +		DBG_DO(if (!ao_lisp_exception && ao_lisp_poly_builtin(ao_lisp_v)->func == builtin_set) { +				struct ao_lisp_cons *cons = ao_lisp_poly_cons(ao_lisp_stack->values); +				ao_poly atom = ao_lisp_arg(cons, 1); +				ao_poly val = ao_lisp_arg(cons, 2); +				DBGI("set "); DBG_POLY(atom); DBG(" = "); DBG_POLY(val); DBG("\n"); +			}); +		builtin = ao_lisp_poly_builtin(ao_lisp_v); +		if (builtin->args & AO_LISP_FUNC_FREE_ARGS && !ao_lisp_stack_marked(ao_lisp_stack)) +			ao_lisp_cons_free(ao_lisp_poly_cons(ao_lisp_stack->values)); + +		ao_lisp_v = v; +		ao_lisp_stack->values = AO_LISP_NIL; +		ao_lisp_stack->values_tail = AO_LISP_NIL; +		DBGI(".. result "); DBG_POLY(ao_lisp_v); DBG ("\n"); +		DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); +		break; +	case AO_LISP_LAMBDA: +		DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); +		ao_lisp_stack->state = eval_progn; +		v = ao_lisp_lambda_eval(); +		ao_lisp_stack->sexprs = v; +		ao_lisp_stack->values = AO_LISP_NIL; +		ao_lisp_stack->values_tail = AO_LISP_NIL; +		DBGI(".. sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); +		DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); +		break; +	case AO_LISP_STACK: +		DBGI(".. stack "); DBG_POLY(ao_lisp_v); DBG("\n"); +		ao_lisp_v = ao_lisp_stack_eval(); +		DBGI(".. value "); DBG_POLY(ao_lisp_v); DBG("\n"); +		DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); +		break; +	} +	return 1; +} + +/* + * Start evaluating the next cond clause + * + * If the list of clauses is empty, then + * the result of the cond is nil. + * + * Otherwise, set the current stack state to 'cond_test' and create a + * new stack context to evaluate the test s-expression. Once that's + * complete, we'll land in 'cond_test' to finish the clause. + */ +static int +ao_lisp_eval_cond(void) +{ +	DBGI("cond: "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); +	DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); +	DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n"); +	if (!ao_lisp_stack->sexprs) { +		ao_lisp_v = AO_LISP_NIL; +		ao_lisp_stack->state = eval_val; +	} else { +		ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car; +		if (!ao_lisp_v || ao_lisp_poly_type(ao_lisp_v) != AO_LISP_CONS) { +			ao_lisp_error(AO_LISP_INVALID, "invalid cond clause"); +			return 0; +		} +		ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car; +		ao_lisp_stack->state = eval_cond_test; +		if (!ao_lisp_stack_push()) +			return 0; +	} +	return 1; +} + +/* + * Finish a cond clause. + * + * Check the value from the test expression, if + * non-nil, then set up to evaluate the value expression. + * + * Otherwise, step to the next clause and go back to the 'cond' + * state + */ +static int +ao_lisp_eval_cond_test(void) +{ +	DBGI("cond_test: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); +	DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); +	DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n"); +	if (ao_lisp_v) { +		struct ao_lisp_cons *car = ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car); +		ao_poly c = car->cdr; + +		if (c) { +			ao_lisp_stack->state = eval_progn; +			ao_lisp_stack->sexprs = c; +		} else +			ao_lisp_stack->state = eval_val; +	} else { +		ao_lisp_stack->sexprs = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr; +		DBGI("next cond: "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); +		ao_lisp_stack->state = eval_cond; +	} +	return 1; +} + +/* + * Evaluate a list of sexprs, returning the value from the last one. + * + * ao_lisp_progn records the list in stack->sexprs, so we just need to + * walk that list. Set ao_lisp_v to the car of the list and jump to + * eval_sexpr. When that's done, it will land in eval_val. For all but + * the last, leave a stack frame with eval_progn set so that we come + * back here. For the last, don't add a stack frame so that we can + * just continue on. + */ +static int +ao_lisp_eval_progn(void) +{ +	DBGI("progn: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); +	DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); +	DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n"); + +	if (!ao_lisp_stack->sexprs) { +		ao_lisp_v = AO_LISP_NIL; +		ao_lisp_stack->state = eval_val; +	} else { +		ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car; +		ao_lisp_stack->sexprs = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr; + +		/* If there are more sexprs to do, then come back here, otherwise +		 * return the value of the last one by just landing in eval_sexpr +		 */ +		if (ao_lisp_stack->sexprs) { +			ao_lisp_stack->state = eval_progn; +			if (!ao_lisp_stack_push()) +				return 0; +		} +		ao_lisp_stack->state = eval_sexpr; +	} +	return 1; +} + +/* + * Conditionally execute a list of sexprs while the first is true + */ +static int +ao_lisp_eval_while(void) +{ +	DBGI("while: "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); +	DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); +	DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n"); + +	ao_lisp_stack->values = ao_lisp_v; +	if (!ao_lisp_stack->sexprs) { +		ao_lisp_v = AO_LISP_NIL; +		ao_lisp_stack->state = eval_val; +	} else { +		ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car; +		ao_lisp_stack->state = eval_while_test; +		if (!ao_lisp_stack_push()) +			return 0; +	} +	return 1; +} + +/* + * Check the while condition, terminate the loop if nil. Otherwise keep going + */ +static int +ao_lisp_eval_while_test(void) +{ +	DBGI("while_test: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); +	DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); +	DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n"); + +	if (ao_lisp_v) { +		ao_lisp_stack->values = ao_lisp_v; +		ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr; +		ao_lisp_stack->state = eval_while; +		if (!ao_lisp_stack_push()) +			return 0; +		ao_lisp_stack->state = eval_progn; +		ao_lisp_stack->sexprs = ao_lisp_v; +	} +	else +	{ +		ao_lisp_stack->state = eval_val; +		ao_lisp_v = ao_lisp_stack->values; +	} +	return 1; +} + +/* + * Replace the original sexpr with the macro expansion, then + * execute that + */ +static int +ao_lisp_eval_macro(void) +{ +	DBGI("macro: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); + +	if (ao_lisp_v == AO_LISP_NIL) +		ao_lisp_abort(); +	if (ao_lisp_poly_type(ao_lisp_v) == AO_LISP_CONS) { +		*ao_lisp_poly_cons(ao_lisp_stack->sexprs) = *ao_lisp_poly_cons(ao_lisp_v); +		ao_lisp_v = ao_lisp_stack->sexprs; +		DBGI("sexprs rewritten to: "); DBG_POLY(ao_lisp_v); DBG("\n"); +	} +	ao_lisp_stack->sexprs = AO_LISP_NIL; +	ao_lisp_stack->state = eval_sexpr; +	return 1; +} + +static int (*const evals[])(void) = { +	[eval_sexpr] = ao_lisp_eval_sexpr, +	[eval_val] = ao_lisp_eval_val, +	[eval_formal] = ao_lisp_eval_formal, +	[eval_exec] = ao_lisp_eval_exec, +	[eval_cond] = ao_lisp_eval_cond, +	[eval_cond_test] = ao_lisp_eval_cond_test, +	[eval_progn] = ao_lisp_eval_progn, +	[eval_while] = ao_lisp_eval_while, +	[eval_while_test] = ao_lisp_eval_while_test, +	[eval_macro] = ao_lisp_eval_macro, +}; + +const char *ao_lisp_state_names[] = { +	"sexpr", +	"val", +	"formal", +	"exec", +	"cond", +	"cond_test", +	"progn", +}; + +/* + * Called at restore time to reset all execution state + */ + +void +ao_lisp_eval_clear_globals(void) +{ +	ao_lisp_stack = NULL; +	ao_lisp_frame_current = NULL; +	ao_lisp_v = AO_LISP_NIL; +} + +int +ao_lisp_eval_restart(void) +{ +	return ao_lisp_stack_push(); +} + +ao_poly +ao_lisp_eval(ao_poly _v) +{ +	ao_lisp_v = _v; + +	if (!ao_lisp_stack_push()) +		return AO_LISP_NIL; + +	while (ao_lisp_stack) { +		if (!(*evals[ao_lisp_stack->state])() || ao_lisp_exception) { +			ao_lisp_stack_clear(); +			return AO_LISP_NIL; +		} +	} +	DBG_DO(if (ao_lisp_frame_current) {DBGI("frame left as "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");}); +	ao_lisp_frame_current = NULL; +	return ao_lisp_v; +} diff --git a/src/lisp/ao_lisp_frame.c b/src/lisp/ao_lisp_frame.c new file mode 100644 index 00000000..05f6d253 --- /dev/null +++ b/src/lisp/ao_lisp_frame.c @@ -0,0 +1,293 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" + +static inline int +frame_num_size(int num) +{ +	return sizeof (struct ao_lisp_frame) + num * sizeof (struct ao_lisp_val); +} + +static int +frame_size(void *addr) +{ +	struct ao_lisp_frame	*frame = addr; +	return frame_num_size(frame->num); +} + +static void +frame_mark(void *addr) +{ +	struct ao_lisp_frame	*frame = addr; +	int			f; + +	for (;;) { +		MDBG_MOVE("frame mark %d\n", MDBG_OFFSET(frame)); +		if (!AO_LISP_IS_POOL(frame)) +			break; +		for (f = 0; f < frame->num; f++) { +			struct ao_lisp_val	*v = &frame->vals[f]; + +			ao_lisp_poly_mark(v->val, 0); +			MDBG_MOVE("frame mark atom %s %d val %d at %d\n", +				  ao_lisp_poly_atom(v->atom)->name, +				  MDBG_OFFSET(ao_lisp_ref(v->atom)), +				  MDBG_OFFSET(ao_lisp_ref(v->val)), f); +		} +		frame = ao_lisp_poly_frame(frame->prev); +		MDBG_MOVE("frame next %d\n", MDBG_OFFSET(frame)); +		if (!frame) +			break; +		if (ao_lisp_mark_memory(&ao_lisp_frame_type, frame)) +			break; +	} +} + +static void +frame_move(void *addr) +{ +	struct ao_lisp_frame	*frame = addr; +	int			f; + +	for (;;) { +		struct ao_lisp_frame	*prev; +		int			ret; + +		MDBG_MOVE("frame move %d\n", MDBG_OFFSET(frame)); +		if (!AO_LISP_IS_POOL(frame)) +			break; +		for (f = 0; f < frame->num; f++) { +			struct ao_lisp_val	*v = &frame->vals[f]; + +			ao_lisp_poly_move(&v->atom, 0); +			ao_lisp_poly_move(&v->val, 0); +			MDBG_MOVE("frame move atom %s %d val %d at %d\n", +				  ao_lisp_poly_atom(v->atom)->name, +				  MDBG_OFFSET(ao_lisp_ref(v->atom)), +				  MDBG_OFFSET(ao_lisp_ref(v->val)), f); +		} +		prev = ao_lisp_poly_frame(frame->prev); +		if (!prev) +			break; +		ret = ao_lisp_move_memory(&ao_lisp_frame_type, (void **) &prev); +		if (prev != ao_lisp_poly_frame(frame->prev)) { +			MDBG_MOVE("frame prev moved from %d to %d\n", +				  MDBG_OFFSET(ao_lisp_poly_frame(frame->prev)), +				  MDBG_OFFSET(prev)); +			frame->prev = ao_lisp_frame_poly(prev); +		} +		if (ret) +			break; +		frame = prev; +	} +} + +const struct ao_lisp_type ao_lisp_frame_type = { +	.mark = frame_mark, +	.size = frame_size, +	.move = frame_move, +	.name = "frame", +}; + +void +ao_lisp_frame_print(ao_poly p) +{ +	struct ao_lisp_frame	*frame = ao_lisp_poly_frame(p); +	int			f; + +	printf ("{"); +	if (frame) { +		if (frame->type & AO_LISP_FRAME_PRINT) +			printf("recurse..."); +		else { +			frame->type |= AO_LISP_FRAME_PRINT; +			for (f = 0; f < frame->num; f++) { +				if (f != 0) +					printf(", "); +				ao_lisp_poly_print(frame->vals[f].atom); +				printf(" = "); +				ao_lisp_poly_print(frame->vals[f].val); +			} +			if (frame->prev) +				ao_lisp_poly_print(frame->prev); +			frame->type &= ~AO_LISP_FRAME_PRINT; +		} +	} +	printf("}"); +} + +static int +ao_lisp_frame_find(struct ao_lisp_frame *frame, int top, ao_poly atom) +{ +	int l = 0; +	int r = top - 1; +	while (l <= r) { +		int m = (l + r) >> 1; +		if (frame->vals[m].atom < atom) +			l = m + 1; +		else +			r = m - 1; +	} +	return l; +} + +ao_poly * +ao_lisp_frame_ref(struct ao_lisp_frame *frame, ao_poly atom) +{ +	int l = ao_lisp_frame_find(frame, frame->num, atom); + +	if (l >= frame->num) +		return NULL; + +	if (frame->vals[l].atom != atom) +		return NULL; +	return &frame->vals[l].val; +} + +int +ao_lisp_frame_set(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val) +{ +	while (frame) { +		if (!AO_LISP_IS_CONST(frame)) { +			ao_poly *ref = ao_lisp_frame_ref(frame, atom); +			if (ref) { +				*ref = val; +				return 1; +			} +		} +		frame = ao_lisp_poly_frame(frame->prev); +	} +	return 0; +} + +ao_poly +ao_lisp_frame_get(struct ao_lisp_frame *frame, ao_poly atom) +{ +	while (frame) { +		ao_poly *ref = ao_lisp_frame_ref(frame, atom); +		if (ref) +			return *ref; +		frame = ao_lisp_poly_frame(frame->prev); +	} +	return AO_LISP_NIL; +} + +struct ao_lisp_frame	*ao_lisp_frame_free_list[AO_LISP_FRAME_FREE]; + +struct ao_lisp_frame * +ao_lisp_frame_new(int num) +{ +	struct ao_lisp_frame	*frame; + +	if (num < AO_LISP_FRAME_FREE && (frame = ao_lisp_frame_free_list[num])) +		ao_lisp_frame_free_list[num] = ao_lisp_poly_frame(frame->prev); +	else { +		frame = ao_lisp_alloc(frame_num_size(num)); +		if (!frame) +			return NULL; +	} +	frame->type = AO_LISP_FRAME; +	frame->num = num; +	frame->prev = AO_LISP_NIL; +	memset(frame->vals, '\0', num * sizeof (struct ao_lisp_val)); +	return frame; +} + +ao_poly +ao_lisp_frame_mark(struct ao_lisp_frame *frame) +{ +	if (!frame) +		return AO_LISP_NIL; +	frame->type |= AO_LISP_FRAME_MARK; +	return ao_lisp_frame_poly(frame); +} + +void +ao_lisp_frame_free(struct ao_lisp_frame *frame) +{ +	if (!ao_lisp_frame_marked(frame)) { +		int	num = frame->num; +		if (num < AO_LISP_FRAME_FREE) { +			frame->prev = ao_lisp_frame_poly(ao_lisp_frame_free_list[num]); +			ao_lisp_frame_free_list[num] = frame; +		} +	} +} + +static struct ao_lisp_frame * +ao_lisp_frame_realloc(struct ao_lisp_frame **frame_ref, int new_num) +{ +	struct ao_lisp_frame	*frame = *frame_ref; +	struct ao_lisp_frame	*new; +	int			copy; + +	if (new_num == frame->num) +		return frame; +	new = ao_lisp_frame_new(new_num); +	if (!new) +		return NULL; +	/* +	 * Re-fetch the frame as it may have moved +	 * during the allocation +	 */ +	frame = *frame_ref; +	copy = new_num; +	if (copy > frame->num) +		copy = frame->num; +	memcpy(new->vals, frame->vals, copy * sizeof (struct ao_lisp_val)); +	new->prev = frame->prev; +	ao_lisp_frame_free(frame); +	return new; +} + +void +ao_lisp_frame_bind(struct ao_lisp_frame *frame, int num, ao_poly atom, ao_poly val) +{ +	int l = ao_lisp_frame_find(frame, num, atom); + +	memmove(&frame->vals[l+1], +		&frame->vals[l], +		(num - l) * sizeof (struct ao_lisp_val)); +	frame->vals[l].atom = atom; +	frame->vals[l].val = val; +} + +int +ao_lisp_frame_add(struct ao_lisp_frame **frame_ref, ao_poly atom, ao_poly val) +{ +	struct ao_lisp_frame *frame = *frame_ref; +	ao_poly *ref = frame ? ao_lisp_frame_ref(frame, atom) : NULL; + +	if (!ref) { +		int f; +		ao_lisp_poly_stash(0, atom); +		ao_lisp_poly_stash(1, val); +		if (frame) { +			f = frame->num; +			frame = ao_lisp_frame_realloc(frame_ref, f + 1); +		} else { +			f = 0; +			frame = ao_lisp_frame_new(1); +		} +		if (!frame) +			return 0; +		*frame_ref = frame; +		atom = ao_lisp_poly_fetch(0); +		val = ao_lisp_poly_fetch(1); +		ao_lisp_frame_bind(frame, frame->num - 1, atom, val); +	} else +		*ref = val; +	return 1; +} diff --git a/src/lisp/ao_lisp_int.c b/src/lisp/ao_lisp_int.c new file mode 100644 index 00000000..77f65e95 --- /dev/null +++ b/src/lisp/ao_lisp_int.c @@ -0,0 +1,22 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" + +void +ao_lisp_int_print(ao_poly p) +{ +	int i = ao_lisp_poly_int(p); +	printf("%d", i); +} diff --git a/src/lisp/ao_lisp_lambda.c b/src/lisp/ao_lisp_lambda.c new file mode 100644 index 00000000..526863c5 --- /dev/null +++ b/src/lisp/ao_lisp_lambda.c @@ -0,0 +1,196 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao_lisp.h" + +int +lambda_size(void *addr) +{ +	(void) addr; +	return sizeof (struct ao_lisp_lambda); +} + +void +lambda_mark(void *addr) +{ +	struct ao_lisp_lambda	*lambda = addr; + +	ao_lisp_poly_mark(lambda->code, 0); +	ao_lisp_poly_mark(lambda->frame, 0); +} + +void +lambda_move(void *addr) +{ +	struct ao_lisp_lambda	*lambda = addr; + +	ao_lisp_poly_move(&lambda->code, 0); +	ao_lisp_poly_move(&lambda->frame, 0); +} + +const struct ao_lisp_type ao_lisp_lambda_type = { +	.size = lambda_size, +	.mark = lambda_mark, +	.move = lambda_move, +	.name = "lambda", +}; + +void +ao_lisp_lambda_print(ao_poly poly) +{ +	struct ao_lisp_lambda	*lambda = ao_lisp_poly_lambda(poly); +	struct ao_lisp_cons	*cons = ao_lisp_poly_cons(lambda->code); + +	printf("("); +	printf("%s", ao_lisp_args_name(lambda->args)); +	while (cons) { +		printf(" "); +		ao_lisp_poly_print(cons->car); +		cons = ao_lisp_poly_cons(cons->cdr); +	} +	printf(")"); +} + +ao_poly +ao_lisp_lambda_alloc(struct ao_lisp_cons *code, int args) +{ +	ao_lisp_cons_stash(0, code); +	struct ao_lisp_lambda	*lambda = ao_lisp_alloc(sizeof (struct ao_lisp_lambda)); +	code = ao_lisp_cons_fetch(0); +	struct ao_lisp_cons	*arg; +	int			f; + +	if (!lambda) +		return AO_LISP_NIL; + +	if (!ao_lisp_check_argt(_ao_lisp_atom_lambda, code, 0, AO_LISP_CONS, 1)) +		return AO_LISP_NIL; +	f = 0; +	arg = ao_lisp_poly_cons(ao_lisp_arg(code, 0)); +	while (arg) { +		if (ao_lisp_poly_type(arg->car) != AO_LISP_ATOM) +			return ao_lisp_error(AO_LISP_INVALID, "formal %d is not an atom", f); +		arg = ao_lisp_poly_cons(arg->cdr); +		f++; +	} + +	lambda->type = AO_LISP_LAMBDA; +	lambda->args = args; +	lambda->code = ao_lisp_cons_poly(code); +	lambda->frame = ao_lisp_frame_mark(ao_lisp_frame_current); +	DBGI("build frame: "); DBG_POLY(lambda->frame); DBG("\n"); +	DBG_STACK(); +	return ao_lisp_lambda_poly(lambda); +} + +ao_poly +ao_lisp_lambda(struct ao_lisp_cons *cons) +{ +	return ao_lisp_lambda_alloc(cons, AO_LISP_FUNC_LAMBDA); +} + +ao_poly +ao_lisp_lexpr(struct ao_lisp_cons *cons) +{ +	return ao_lisp_lambda_alloc(cons, AO_LISP_FUNC_LEXPR); +} + +ao_poly +ao_lisp_nlambda(struct ao_lisp_cons *cons) +{ +	return ao_lisp_lambda_alloc(cons, AO_LISP_FUNC_NLAMBDA); +} + +ao_poly +ao_lisp_macro(struct ao_lisp_cons *cons) +{ +	return ao_lisp_lambda_alloc(cons, AO_LISP_FUNC_MACRO); +} + +ao_poly +ao_lisp_lambda_eval(void) +{ +	struct ao_lisp_lambda	*lambda = ao_lisp_poly_lambda(ao_lisp_v); +	struct ao_lisp_cons	*cons = ao_lisp_poly_cons(ao_lisp_stack->values); +	struct ao_lisp_cons	*code = ao_lisp_poly_cons(lambda->code); +	struct ao_lisp_cons	*args = ao_lisp_poly_cons(ao_lisp_arg(code, 0)); +	struct ao_lisp_frame	*next_frame; +	int			args_wanted; +	int			args_provided; +	int			f; +	struct ao_lisp_cons	*vals; + +	DBGI("lambda "); DBG_POLY(ao_lisp_lambda_poly(lambda)); DBG("\n"); + +	args_wanted = ao_lisp_cons_length(args); + +	/* Create a frame to hold the variables +	 */ +	args_provided = ao_lisp_cons_length(cons) - 1; +	if (lambda->args == AO_LISP_FUNC_LAMBDA) { +		if (args_wanted != args_provided) +			return ao_lisp_error(AO_LISP_INVALID, "need %d args, got %d", args_wanted, args_provided); +	} else { +		if (args_provided < args_wanted - 1) +			return ao_lisp_error(AO_LISP_INVALID, "need at least %d args, got %d", args_wanted, args_provided); +	} + +	next_frame = ao_lisp_frame_new(args_wanted); + +	/* Re-fetch all of the values in case something moved */ +	lambda = ao_lisp_poly_lambda(ao_lisp_v); +	cons = ao_lisp_poly_cons(ao_lisp_stack->values); +	code = ao_lisp_poly_cons(lambda->code); +	args = ao_lisp_poly_cons(ao_lisp_arg(code, 0)); +	vals = ao_lisp_poly_cons(cons->cdr); + +	next_frame->prev = lambda->frame; +	ao_lisp_frame_current = next_frame; +	ao_lisp_stack->frame = ao_lisp_frame_poly(ao_lisp_frame_current); + +	switch (lambda->args) { +	case AO_LISP_FUNC_LAMBDA: +		for (f = 0; f < args_wanted; f++) { +			DBGI("bind "); DBG_POLY(args->car); DBG(" = "); DBG_POLY(vals->car); DBG("\n"); +			ao_lisp_frame_bind(next_frame, f, args->car, vals->car); +			args = ao_lisp_poly_cons(args->cdr); +			vals = ao_lisp_poly_cons(vals->cdr); +		} +		if (!ao_lisp_stack_marked(ao_lisp_stack)) +			ao_lisp_cons_free(cons); +		cons = NULL; +		break; +	case AO_LISP_FUNC_LEXPR: +	case AO_LISP_FUNC_NLAMBDA: +	case AO_LISP_FUNC_MACRO: +		for (f = 0; f < args_wanted - 1; f++) { +			DBGI("bind "); DBG_POLY(args->car); DBG(" = "); DBG_POLY(vals->car); DBG("\n"); +			ao_lisp_frame_bind(next_frame, f, args->car, vals->car); +			args = ao_lisp_poly_cons(args->cdr); +			vals = ao_lisp_poly_cons(vals->cdr); +		} +		DBGI("bind "); DBG_POLY(args->car); DBG(" = "); DBG_POLY(ao_lisp_cons_poly(vals)); DBG("\n"); +		ao_lisp_frame_bind(next_frame, f, args->car, ao_lisp_cons_poly(vals)); +		break; +	default: +		break; +	} +	DBGI("eval frame: "); DBG_POLY(ao_lisp_frame_poly(next_frame)); DBG("\n"); +	DBG_STACK(); +	DBGI("eval code: "); DBG_POLY(code->cdr); DBG("\n"); +	return code->cdr; +} diff --git a/src/lisp/ao_lisp_lex.c b/src/lisp/ao_lisp_lex.c new file mode 100644 index 00000000..fe7c47f4 --- /dev/null +++ b/src/lisp/ao_lisp_lex.c @@ -0,0 +1,16 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" + diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c new file mode 100644 index 00000000..49f989e6 --- /dev/null +++ b/src/lisp/ao_lisp_make_const.c @@ -0,0 +1,423 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" +#include <stdlib.h> +#include <ctype.h> +#include <unistd.h> +#include <getopt.h> + +static struct ao_lisp_builtin * +ao_lisp_make_builtin(enum ao_lisp_builtin_id func, int args) { +	struct ao_lisp_builtin *b = ao_lisp_alloc(sizeof (struct ao_lisp_builtin)); + +	b->type = AO_LISP_BUILTIN; +	b->func = func; +	b->args = args; +	return b; +} + +struct builtin_func { +	char	*name; +	int	args; +	int	func; +}; + +struct builtin_func funcs[] = { +	{ .name = "eval",	.args = AO_LISP_FUNC_F_LAMBDA,	.func = builtin_eval }, +	{ .name = "read",	.args = AO_LISP_FUNC_F_LAMBDA,	.func = builtin_read }, +	{ .name = "lambda",	.args = AO_LISP_FUNC_NLAMBDA,	.func = builtin_lambda }, +	{ .name = "lexpr",	.args = AO_LISP_FUNC_NLAMBDA,	.func = builtin_lexpr }, +	{ .name = "nlambda",	.args = AO_LISP_FUNC_NLAMBDA,	.func = builtin_nlambda }, +	{ .name = "macro",	.args = AO_LISP_FUNC_NLAMBDA,	.func = builtin_macro }, +	{ .name = "car",	.args = AO_LISP_FUNC_F_LAMBDA,	.func = builtin_car }, +	{ .name = "cdr",	.args = AO_LISP_FUNC_F_LAMBDA,	.func = builtin_cdr }, +	{ .name = "cons",	.args = AO_LISP_FUNC_F_LAMBDA,	.func = builtin_cons }, +	{ .name = "last",	.args = AO_LISP_FUNC_F_LAMBDA,	.func = builtin_last }, +	{ .name = "length",	.args = AO_LISP_FUNC_F_LAMBDA,	.func = builtin_length }, +	{ .name = "quote",	.args = AO_LISP_FUNC_NLAMBDA,	.func = builtin_quote }, +	{ .name = "set",	.args = AO_LISP_FUNC_F_LAMBDA,	.func = builtin_set }, +	{ .name = "setq",	.args = AO_LISP_FUNC_MACRO,	.func = builtin_setq }, +	{ .name = "cond",	.args = AO_LISP_FUNC_NLAMBDA,	.func = builtin_cond }, +	{ .name = "progn",	.args = AO_LISP_FUNC_NLAMBDA,	.func = builtin_progn }, +	{ .name = "while",	.args = AO_LISP_FUNC_NLAMBDA,	.func = builtin_while }, +	{ .name = "print",	.args = AO_LISP_FUNC_F_LEXPR,	.func = builtin_print }, +	{ .name = "patom",	.args = AO_LISP_FUNC_F_LEXPR,	.func = builtin_patom }, +	{ .name = "+",		.args = AO_LISP_FUNC_F_LEXPR,	.func = builtin_plus }, +	{ .name = "-",		.args = AO_LISP_FUNC_F_LEXPR,	.func = builtin_minus }, +	{ .name = "*",		.args = AO_LISP_FUNC_F_LEXPR,	.func = builtin_times }, +	{ .name = "/",		.args = AO_LISP_FUNC_F_LEXPR,	.func = builtin_divide }, +	{ .name = "%",		.args = AO_LISP_FUNC_F_LEXPR,	.func = builtin_mod }, +	{ .name = "=",		.args = AO_LISP_FUNC_F_LEXPR,	.func = builtin_equal }, +	{ .name = "<",		.args = AO_LISP_FUNC_F_LEXPR,	.func = builtin_less }, +	{ .name = ">",		.args = AO_LISP_FUNC_F_LEXPR,	.func = builtin_greater }, +	{ .name = "<=",		.args = AO_LISP_FUNC_F_LEXPR,	.func = builtin_less_equal }, +	{ .name = ">=",		.args = AO_LISP_FUNC_F_LEXPR,	.func = builtin_greater_equal }, +	{ .name = "pack",	.args = AO_LISP_FUNC_F_LAMBDA,	.func = builtin_pack }, +	{ .name = "unpack",	.args = AO_LISP_FUNC_F_LAMBDA,	.func = builtin_unpack }, +	{ .name = "flush",	.args = AO_LISP_FUNC_F_LAMBDA,	.func = builtin_flush }, +	{ .name = "delay",	.args = AO_LISP_FUNC_F_LAMBDA,	.func = builtin_delay }, +	{ .name = "led",	.args = AO_LISP_FUNC_F_LEXPR,	.func = builtin_led }, +	{ .name = "save",	.args = AO_LISP_FUNC_F_LAMBDA,	.func = builtin_save }, +	{ .name = "restore",	.args = AO_LISP_FUNC_F_LAMBDA,	.func = builtin_restore }, +	{ .name = "call/cc",	.args = AO_LISP_FUNC_F_LAMBDA,	.func = builtin_call_cc }, +	{ .name = "collect",	.args = AO_LISP_FUNC_F_LAMBDA,	.func = builtin_collect }, +}; + +#define N_FUNC (sizeof funcs / sizeof funcs[0]) + +struct ao_lisp_frame	*globals; + +static int +is_atom(int offset) +{ +	struct ao_lisp_atom *a; + +	for (a = ao_lisp_atoms; a; a = ao_lisp_poly_atom(a->next)) +		if (((uint8_t *) a->name - ao_lisp_const) == offset) +			return strlen(a->name); +	return 0; +} + +#define AO_FEC_CRC_INIT	0xffff + +static inline uint16_t +ao_fec_crc_byte(uint8_t byte, uint16_t crc) +{ +	uint8_t	bit; + +	for (bit = 0; bit < 8; bit++) { +		if (((crc & 0x8000) >> 8) ^ (byte & 0x80)) +			crc = (crc << 1) ^ 0x8005; +		else +			crc = (crc << 1); +		byte <<= 1; +	} +	return crc; +} + +uint16_t +ao_fec_crc(const uint8_t *bytes, uint8_t len) +{ +	uint16_t	crc = AO_FEC_CRC_INIT; + +	while (len--) +		crc = ao_fec_crc_byte(*bytes++, crc); +	return crc; +} + +struct ao_lisp_macro_stack { +	struct ao_lisp_macro_stack *next; +	ao_poly	p; +}; + +struct ao_lisp_macro_stack *macro_stack; + +int +ao_lisp_macro_push(ao_poly p) +{ +	struct ao_lisp_macro_stack *m = macro_stack; + +	while (m) { +		if (m->p == p) +			return 1; +		m = m->next; +	} +	m = malloc (sizeof (struct ao_lisp_macro_stack)); +	m->p = p; +	m->next = macro_stack; +	macro_stack = m; +	return 0; +} + +void +ao_lisp_macro_pop(void) +{ +	struct ao_lisp_macro_stack *m = macro_stack; + +	macro_stack = m->next; +	free(m); +} + +#define DBG_MACRO 0 +#if DBG_MACRO +int macro_scan_depth; + +void indent(void) +{ +	int i; +	for (i = 0; i < macro_scan_depth; i++) +		printf("  "); +} +#define MACRO_DEBUG(a)	a +#else +#define MACRO_DEBUG(a) +#endif + +ao_poly +ao_has_macro(ao_poly p); + +ao_poly +ao_macro_test_get(ao_poly atom) +{ +	ao_poly	*ref = ao_lisp_atom_ref(ao_lisp_frame_global, atom); +	if (ref) +		return *ref; +	return AO_LISP_NIL; +} + +ao_poly +ao_is_macro(ao_poly p) +{ +	struct ao_lisp_builtin	*builtin; +	struct ao_lisp_lambda	*lambda; +	ao_poly ret; + +	MACRO_DEBUG(indent(); printf ("is macro "); ao_lisp_poly_print(p); printf("\n"); ++macro_scan_depth); +	switch (ao_lisp_poly_type(p)) { +	case AO_LISP_ATOM: +		if (ao_lisp_macro_push(p)) +			ret = AO_LISP_NIL; +		else { +			if (ao_is_macro(ao_macro_test_get(p))) +				ret = p; +			else +				ret = AO_LISP_NIL; +			ao_lisp_macro_pop(); +		} +		break; +	case AO_LISP_CONS: +		ret = ao_has_macro(p); +		break; +	case AO_LISP_BUILTIN: +		builtin = ao_lisp_poly_builtin(p); +		if ((builtin->args & AO_LISP_FUNC_MASK) == AO_LISP_FUNC_MACRO) +			ret = p; +		else +			ret = 0; +		break; + +	case AO_LISP_LAMBDA: +		lambda = ao_lisp_poly_lambda(p); +		if (lambda->args == AO_LISP_FUNC_MACRO) +			ret = p; +		else +			ret = ao_has_macro(lambda->code); +		break; +	default: +		ret = AO_LISP_NIL; +		break; +	} +	MACRO_DEBUG(--macro_scan_depth;	indent(); printf ("... "); ao_lisp_poly_print(ret); printf("\n")); +	return ret; +} + +ao_poly +ao_has_macro(ao_poly p) +{ +	struct ao_lisp_cons	*cons; +	struct ao_lisp_lambda	*lambda; +	ao_poly			m; + +	if (p == AO_LISP_NIL) +		return AO_LISP_NIL; + +	MACRO_DEBUG(indent(); printf("has macro "); ao_lisp_poly_print(p); printf("\n"); ++macro_scan_depth); +	switch (ao_lisp_poly_type(p)) { +	case AO_LISP_LAMBDA: +		lambda = ao_lisp_poly_lambda(p); +		p = ao_has_macro(lambda->code); +		break; +	case AO_LISP_CONS: +		cons = ao_lisp_poly_cons(p); +		if ((p = ao_is_macro(cons->car))) +			break; + +		cons = ao_lisp_poly_cons(cons->cdr); +		p = AO_LISP_NIL; +		while (cons) { +			m = ao_has_macro(cons->car); +			if (m) { +				p = m; +				break; +			} +			cons = ao_lisp_poly_cons(cons->cdr); +		} +		break; + +	default: +		p = AO_LISP_NIL; +		break; +	} +	MACRO_DEBUG(--macro_scan_depth;	indent(); printf("... "); ao_lisp_poly_print(p); printf("\n")); +	return p; +} + +int +ao_lisp_read_eval_abort(void) +{ +	ao_poly	in, out = AO_LISP_NIL; +	for(;;) { +		in = ao_lisp_read(); +		if (in == _ao_lisp_atom_eof) +			break; +		out = ao_lisp_eval(in); +		if (ao_lisp_exception) +			return 0; +		ao_lisp_poly_print(out); +		putchar ('\n'); +	} +	return 1; +} + +static FILE	*in; +static FILE	*out; + +int +ao_lisp_getc(void) +{ +	return getc(in); +} + +static const struct option options[] = { +	{ .name = "out", .has_arg = 1, .val = 'o' }, +	{ 0, 0, 0, 0 } +}; + +static void usage(char *program) +{ +	fprintf(stderr, "usage: %s [--out=<output>] [input]\n", program); +	exit(1); +} + +int +main(int argc, char **argv) +{ +	int	f, o; +	ao_poly	val; +	struct ao_lisp_atom	*a; +	struct ao_lisp_builtin	*b; +	int	in_atom = 0; +	char	*out_name = NULL; +	int	c; + +	in = stdin; +	out = stdout; + +	while ((c = getopt_long(argc, argv, "o:", options, NULL)) != -1) { +		switch (c) { +		case 'o': +			out_name = optarg; +			break; +		default: +			usage(argv[0]); +			break; +		} +	} + +	for (f = 0; f < (int) N_FUNC; f++) { +		b = ao_lisp_make_builtin(funcs[f].func, funcs[f].args); +		a = ao_lisp_atom_intern(funcs[f].name); +		ao_lisp_atom_set(ao_lisp_atom_poly(a), +				 ao_lisp_builtin_poly(b)); +	} + +	/* boolean constants */ +	ao_lisp_atom_set(ao_lisp_atom_poly(ao_lisp_atom_intern("nil")), +			 AO_LISP_NIL); +	a = ao_lisp_atom_intern("t"); +	ao_lisp_atom_set(ao_lisp_atom_poly(a), +			 ao_lisp_atom_poly(a)); + +	/* end of file value */ +	a = ao_lisp_atom_intern("eof"); +	ao_lisp_atom_set(ao_lisp_atom_poly(a), +			 ao_lisp_atom_poly(a)); + +	if (argv[optind]){ +		in = fopen(argv[optind], "r"); +		if (!in) { +			perror(argv[optind]); +			exit(1); +		} +	} +	if (!ao_lisp_read_eval_abort()) { +		fprintf(stderr, "eval failed\n"); +		exit(1); +	} + +	/* Reduce to referenced values */ +	ao_lisp_collect(AO_LISP_COLLECT_FULL); + +	for (f = 0; f < ao_lisp_frame_global->num; f++) { +		val = ao_has_macro(ao_lisp_frame_global->vals[f].val); +		if (val != AO_LISP_NIL) { +			printf("error: function %s contains unresolved macro: ", +			       ao_lisp_poly_atom(ao_lisp_frame_global->vals[f].atom)->name); +			ao_lisp_poly_print(val); +			printf("\n"); +			exit(1); +		} +	} + +	if (out_name) { +		out = fopen(out_name, "w"); +		if (!out) { +			perror(out_name); +			exit(1); +		} +	} + +	fprintf(out, "/* Generated file, do not edit */\n\n"); + +	fprintf(out, "#define AO_LISP_POOL_CONST %d\n", ao_lisp_top); +	fprintf(out, "extern const uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4)));\n"); +	fprintf(out, "#define ao_builtin_atoms 0x%04x\n", ao_lisp_atom_poly(ao_lisp_atoms)); +	fprintf(out, "#define ao_builtin_frame 0x%04x\n", ao_lisp_frame_poly(ao_lisp_frame_global)); +	fprintf(out, "#define ao_lisp_const_checksum ((uint16_t) 0x%04x)\n", ao_fec_crc(ao_lisp_const, ao_lisp_top)); + + +	for (a = ao_lisp_atoms; a; a = ao_lisp_poly_atom(a->next)) { +		char	*n = a->name, c; +		fprintf(out, "#define _ao_lisp_atom_"); +		while ((c = *n++)) { +			if (isalnum(c)) +				fprintf(out, "%c", c); +			else +				fprintf(out, "%02x", c); +		} +		fprintf(out, "  0x%04x\n", ao_lisp_atom_poly(a)); +	} +	fprintf(out, "#ifdef AO_LISP_CONST_BITS\n"); +	fprintf(out, "const uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute((aligned(4))) = {"); +	for (o = 0; o < ao_lisp_top; o++) { +		uint8_t	c; +		if ((o & 0xf) == 0) +			fprintf(out, "\n\t"); +		else +			fprintf(out, " "); +		c = ao_lisp_const[o]; +		if (!in_atom) +			in_atom = is_atom(o); +		if (in_atom) { +			fprintf(out, " '%c',", c); +			in_atom--; +		} else { +			fprintf(out, "0x%02x,", c); +		} +	} +	fprintf(out, "\n};\n"); +	fprintf(out, "#endif /* AO_LISP_CONST_BITS */\n"); +	exit(0); +} diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c new file mode 100644 index 00000000..d067ea07 --- /dev/null +++ b/src/lisp/ao_lisp_mem.c @@ -0,0 +1,880 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#define AO_LISP_CONST_BITS + +#include "ao_lisp.h" +#include <stdio.h> + +#ifdef AO_LISP_MAKE_CONST + +/* + * When building the constant table, it is the + * pool for allocations. + */ + +#include <stdlib.h> +uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4))); +#define ao_lisp_pool ao_lisp_const +#undef AO_LISP_POOL +#define AO_LISP_POOL AO_LISP_POOL_CONST + +#else + +uint8_t	ao_lisp_pool[AO_LISP_POOL + AO_LISP_POOL_EXTRA] __attribute__((aligned(4))); + +#endif + +#ifndef DBG_MEM_STATS +#define DBG_MEM_STATS	DBG_MEM +#endif + +#if DBG_MEM +int dbg_move_depth; +int dbg_mem = DBG_MEM_START; +int dbg_validate = 0; + +struct ao_lisp_record { +	struct ao_lisp_record		*next; +	const struct ao_lisp_type	*type; +	void				*addr; +	int				size; +}; + +static struct ao_lisp_record	*record_head, **record_tail; + +static void +ao_lisp_record_free(struct ao_lisp_record *record) +{ +	while (record) { +		struct ao_lisp_record *next = record->next; +		free(record); +		record = next; +	} +} + +static void +ao_lisp_record_reset(void) +{ +	ao_lisp_record_free(record_head); +	record_head = NULL; +	record_tail = &record_head; +} + +static void +ao_lisp_record(const struct ao_lisp_type	*type, +	       void				*addr, +	       int				size) +{ +	struct ao_lisp_record	*r = malloc(sizeof (struct ao_lisp_record)); + +	r->next = NULL; +	r->type = type; +	r->addr = addr; +	r->size = size; +	*record_tail = r; +	record_tail = &r->next; +} + +static struct ao_lisp_record * +ao_lisp_record_save(void) +{ +	struct ao_lisp_record *r = record_head; + +	record_head = NULL; +	record_tail = &record_head; +	return r; +} + +static void +ao_lisp_record_compare(char *where, +		       struct ao_lisp_record *a, +		       struct ao_lisp_record *b) +{ +	while (a && b) { +		if (a->type != b->type || a->size != b->size) { +			printf("%s record difers %d %s %d -> %d %s %d\n", +			       where, +			       MDBG_OFFSET(a->addr), +			       a->type->name, +			       a->size, +			       MDBG_OFFSET(b->addr), +			       b->type->name, +			       b->size); +			ao_lisp_abort(); +		} +		a = a->next; +		b = b->next; +	} +	if (a) { +		printf("%s record differs %d %s %d -> NULL\n", +		       where, +		       MDBG_OFFSET(a->addr), +		       a->type->name, +		       a->size); +		ao_lisp_abort(); +	} +	if (b) { +		printf("%s record differs NULL -> %d %s %d\n", +		       where, +		       MDBG_OFFSET(b->addr), +		       b->type->name, +		       b->size); +		ao_lisp_abort(); +	} +} + +#else +#define ao_lisp_record_reset() +#endif + +uint8_t	ao_lisp_exception; + +struct ao_lisp_root { +	const struct ao_lisp_type	*type; +	void				**addr; +}; + +static struct ao_lisp_cons 	*save_cons[2]; +static char			*save_string[2]; +static ao_poly			save_poly[3]; + +static const struct ao_lisp_root	ao_lisp_root[] = { +	{ +		.type = &ao_lisp_cons_type, +		.addr = (void **) &save_cons[0], +	}, +	{ +		.type = &ao_lisp_cons_type, +		.addr = (void **) &save_cons[1], +	}, +	{ +		.type = &ao_lisp_string_type, +		.addr = (void **) &save_string[0], +	}, +	{ +		.type = &ao_lisp_string_type, +		.addr = (void **) &save_string[1], +	}, +	{ +		.type = NULL, +		.addr = (void **) (void *) &save_poly[0] +	}, +	{ +		.type = NULL, +		.addr = (void **) (void *) &save_poly[1] +	}, +	{ +		.type = NULL, +		.addr = (void **) (void *) &save_poly[2] +	}, +	{ +		.type = &ao_lisp_atom_type, +		.addr = (void **) &ao_lisp_atoms +	}, +	{ +		.type = &ao_lisp_frame_type, +		.addr = (void **) &ao_lisp_frame_global, +	}, +	{ +		.type = &ao_lisp_frame_type, +		.addr = (void **) &ao_lisp_frame_current, +	}, +	{ +		.type = &ao_lisp_stack_type, +		.addr = (void **) &ao_lisp_stack, +	}, +	{ +		.type = NULL, +		.addr = (void **) (void *) &ao_lisp_v, +	}, +	{ +		.type = &ao_lisp_cons_type, +		.addr = (void **) &ao_lisp_read_cons, +	}, +	{ +		.type = &ao_lisp_cons_type, +		.addr = (void **) &ao_lisp_read_cons_tail, +	}, +	{ +		.type = &ao_lisp_cons_type, +		.addr = (void **) &ao_lisp_read_stack, +	}, +}; + +#define AO_LISP_ROOT	(sizeof (ao_lisp_root) / sizeof (ao_lisp_root[0])) + +static const void ** const ao_lisp_cache[] = { +	(const void **) &ao_lisp_cons_free_list, +	(const void **) &ao_lisp_stack_free_list, +	(const void **) &ao_lisp_frame_free_list[0], +	(const void **) &ao_lisp_frame_free_list[1], +	(const void **) &ao_lisp_frame_free_list[2], +	(const void **) &ao_lisp_frame_free_list[3], +	(const void **) &ao_lisp_frame_free_list[4], +	(const void **) &ao_lisp_frame_free_list[5], +}; + +#if AO_LISP_FRAME_FREE != 6 +#error Unexpected AO_LISP_FRAME_FREE value +#endif + +#define AO_LISP_CACHE	(sizeof (ao_lisp_cache) / sizeof (ao_lisp_cache[0])) + +#define AO_LISP_BUSY_SIZE	((AO_LISP_POOL + 31) / 32) + +static uint8_t	ao_lisp_busy[AO_LISP_BUSY_SIZE]; +static uint8_t	ao_lisp_cons_note[AO_LISP_BUSY_SIZE]; +static uint8_t	ao_lisp_cons_last[AO_LISP_BUSY_SIZE]; +static uint8_t	ao_lisp_cons_noted; + +uint16_t	ao_lisp_top; + +struct ao_lisp_chunk { +	uint16_t		old_offset; +	union { +		uint16_t	size; +		uint16_t	new_offset; +	}; +}; + +#define AO_LISP_NCHUNK	64 + +static struct ao_lisp_chunk ao_lisp_chunk[AO_LISP_NCHUNK]; + +/* Offset of an address within the pool. */ +static inline uint16_t pool_offset(void *addr) { +#if DBG_MEM +	if (!AO_LISP_IS_POOL(addr)) +		ao_lisp_abort(); +#endif +	return ((uint8_t *) addr) - ao_lisp_pool; +} + +static inline void mark(uint8_t *tag, int offset) { +	int	byte = offset >> 5; +	int	bit = (offset >> 2) & 7; +	tag[byte] |= (1 << bit); +} + +static inline void clear(uint8_t *tag, int offset) { +	int	byte = offset >> 5; +	int	bit = (offset >> 2) & 7; +	tag[byte] &= ~(1 << bit); +} + +static inline int busy(uint8_t *tag, int offset) { +	int	byte = offset >> 5; +	int	bit = (offset >> 2) & 7; +	return (tag[byte] >> bit) & 1; +} + +static inline int min(int a, int b) { return a < b ? a : b; } +static inline int max(int a, int b) { return a > b ? a : b; } + +static inline int limit(int offset) { +	return min(AO_LISP_POOL, max(offset, 0)); +} + +static void +note_cons(uint16_t offset) +{ +	MDBG_MOVE("note cons %d\n", offset); +	ao_lisp_cons_noted = 1; +	mark(ao_lisp_cons_note, offset); +} + +static uint16_t	chunk_low, chunk_high; +static uint16_t	chunk_first, chunk_last; + +static int +find_chunk(uint16_t offset) +{ +	int l, r; +	/* Binary search for the location */ +	l = chunk_first; +	r = chunk_last - 1; +	while (l <= r) { +		int m = (l + r) >> 1; +		if (ao_lisp_chunk[m].old_offset < offset) +			l = m + 1; +		else +			r = m - 1; +	} +	return l; +} + +static void +note_chunk(uint16_t offset, uint16_t size) +{ +	int l; + +	if (offset < chunk_low || chunk_high <= offset) +		return; + +	l = find_chunk(offset); + +	/* +	 * The correct location is always in 'l', with r = l-1 being +	 * the entry before the right one +	 */ + +#if DBG_MEM +	/* Off the right side */ +	if (l >= AO_LISP_NCHUNK) +		ao_lisp_abort(); + +	/* Off the left side */ +	if (l == 0 && chunk_last && offset > ao_lisp_chunk[0].old_offset) +		ao_lisp_abort(); +#endif + +	/* Shuffle existing entries right */ +	int end = min(AO_LISP_NCHUNK, chunk_last + 1); + +	memmove(&ao_lisp_chunk[l+1], +		&ao_lisp_chunk[l], +		(end - (l+1)) * sizeof (struct ao_lisp_chunk)); + +	/* Add new entry */ +	ao_lisp_chunk[l].old_offset = offset; +	ao_lisp_chunk[l].size = size; + +	/* Increment the number of elements up to the size of the array */ +	if (chunk_last < AO_LISP_NCHUNK) +		chunk_last++; + +	/* Set the top address if the array is full */ +	if (chunk_last == AO_LISP_NCHUNK) +		chunk_high = ao_lisp_chunk[AO_LISP_NCHUNK-1].old_offset + +			ao_lisp_chunk[AO_LISP_NCHUNK-1].size; +} + +static void +reset_chunks(void) +{ +	chunk_high = ao_lisp_top; +	chunk_last = 0; +	chunk_first = 0; +} + +/* + * Walk all referenced objects calling functions on each one + */ + +static void +walk(int (*visit_addr)(const struct ao_lisp_type *type, void **addr), +     int (*visit_poly)(ao_poly *p, uint8_t do_note_cons)) +{ +	int i; + +	ao_lisp_record_reset(); +	memset(ao_lisp_busy, '\0', sizeof (ao_lisp_busy)); +	memset(ao_lisp_cons_note, '\0', sizeof (ao_lisp_cons_note)); +	ao_lisp_cons_noted = 0; +	for (i = 0; i < (int) AO_LISP_ROOT; i++) { +		if (ao_lisp_root[i].type) { +			void **a = ao_lisp_root[i].addr, *v; +			if (a && (v = *a)) { +				MDBG_MOVE("root ptr %d\n", MDBG_OFFSET(v)); +				visit_addr(ao_lisp_root[i].type, a); +			} +		} else { +			ao_poly *a = (ao_poly *) ao_lisp_root[i].addr, p; +			if (a && (p = *a)) { +				MDBG_MOVE("root poly %d\n", MDBG_OFFSET(ao_lisp_ref(p))); +				visit_poly(a, 0); +			} +		} +	} +	while (ao_lisp_cons_noted) { +		memcpy(ao_lisp_cons_last, ao_lisp_cons_note, sizeof (ao_lisp_cons_note)); +		memset(ao_lisp_cons_note, '\0', sizeof (ao_lisp_cons_note)); +		ao_lisp_cons_noted = 0; +		for (i = 0; i < AO_LISP_POOL; i += 4) { +			if (busy(ao_lisp_cons_last, i)) { +				void *v = ao_lisp_pool + i; +				MDBG_MOVE("root cons %d\n", MDBG_OFFSET(v)); +				visit_addr(&ao_lisp_cons_type, &v); +			} +		} +	} +} + +#if MDBG_DUMP +static void +dump_busy(void) +{ +	int	i; +	MDBG_MOVE("busy:"); +	for (i = 0; i < ao_lisp_top; i += 4) { +		if ((i & 0xff) == 0) { +			MDBG_MORE("\n"); +			MDBG_MOVE("%s", ""); +		} +		else if ((i & 0x1f) == 0) +			MDBG_MORE(" "); +		if (busy(ao_lisp_busy, i)) +			MDBG_MORE("*"); +		else +			MDBG_MORE("-"); +	} +	MDBG_MORE ("\n"); +} +#define DUMP_BUSY()	dump_busy() +#else +#define DUMP_BUSY() +#endif + +static const struct ao_lisp_type const *ao_lisp_types[AO_LISP_NUM_TYPE] = { +	[AO_LISP_CONS] = &ao_lisp_cons_type, +	[AO_LISP_INT] = NULL, +	[AO_LISP_STRING] = &ao_lisp_string_type, +	[AO_LISP_OTHER] = (void *) 0x1, +	[AO_LISP_ATOM] = &ao_lisp_atom_type, +	[AO_LISP_BUILTIN] = &ao_lisp_builtin_type, +	[AO_LISP_FRAME] = &ao_lisp_frame_type, +	[AO_LISP_LAMBDA] = &ao_lisp_lambda_type, +	[AO_LISP_STACK] = &ao_lisp_stack_type, +}; + +static int +ao_lisp_mark_ref(const struct ao_lisp_type *type, void **ref) +{ +	return ao_lisp_mark(type, *ref); +} + +static int +ao_lisp_poly_mark_ref(ao_poly *p, uint8_t do_note_cons) +{ +	return ao_lisp_poly_mark(*p, do_note_cons); +} + +#if DBG_MEM_STATS +int ao_lisp_collects[2]; +int ao_lisp_freed[2]; +int ao_lisp_loops[2]; +#endif + +int ao_lisp_last_top; + +int +ao_lisp_collect(uint8_t style) +{ +	int	i; +	int	top; +#if DBG_MEM_STATS +	int	loops = 0; +#endif +#if DBG_MEM +	struct ao_lisp_record	*mark_record = NULL, *move_record = NULL; + +	MDBG_MOVE("collect %d\n", ao_lisp_collects[style]); +#endif + +	/* The first time through, we're doing a full collect */ +	if (ao_lisp_last_top == 0) +		style = AO_LISP_COLLECT_FULL; + +	/* Clear references to all caches */ +	for (i = 0; i < (int) AO_LISP_CACHE; i++) +		*ao_lisp_cache[i] = NULL; +	if (style == AO_LISP_COLLECT_FULL) { +		chunk_low = top = 0; +	} else { +		chunk_low = top = ao_lisp_last_top; +	} +	for (;;) { +#if DBG_MEM_STATS +		loops++; +#endif +		MDBG_MOVE("move chunks from %d to %d\n", chunk_low, top); +		/* Find the sizes of the first chunk of objects to move */ +		reset_chunks(); +		walk(ao_lisp_mark_ref, ao_lisp_poly_mark_ref); +#if DBG_MEM + +		ao_lisp_record_free(mark_record); +		mark_record = ao_lisp_record_save(); +		if (mark_record && move_record) +			ao_lisp_record_compare("mark", move_record, mark_record); +#endif + +		DUMP_BUSY(); + +		/* Find the first moving object */ +		for (i = 0; i < chunk_last; i++) { +			uint16_t	size = ao_lisp_chunk[i].size; + +#if DBG_MEM +			if (!size) +				ao_lisp_abort(); +#endif + +			if (ao_lisp_chunk[i].old_offset > top) +				break; + +			MDBG_MOVE("chunk %d %d not moving\n", +				  ao_lisp_chunk[i].old_offset, +				  ao_lisp_chunk[i].size); +#if DBG_MEM +			if (ao_lisp_chunk[i].old_offset != top) +				ao_lisp_abort(); +#endif +			top += size; +		} + +		/* +		 * Limit amount of chunk array used in mapping moves +		 * to the active region +		 */ +		chunk_first = i; +		chunk_low = ao_lisp_chunk[i].old_offset; + +		/* Copy all of the objects */ +		for (; i < chunk_last; i++) { +			uint16_t	size = ao_lisp_chunk[i].size; + +#if DBG_MEM +			if (!size) +				ao_lisp_abort(); +#endif + +			MDBG_MOVE("chunk %d %d -> %d\n", +				  ao_lisp_chunk[i].old_offset, +				  size, +				  top); +			ao_lisp_chunk[i].new_offset = top; + +			memmove(&ao_lisp_pool[top], +				&ao_lisp_pool[ao_lisp_chunk[i].old_offset], +				size); + +			top += size; +		} + +		if (chunk_first < chunk_last) { +			/* Relocate all references to the objects */ +			walk(ao_lisp_move, ao_lisp_poly_move); + +#if DBG_MEM +			ao_lisp_record_free(move_record); +			move_record = ao_lisp_record_save(); +			if (mark_record && move_record) +				ao_lisp_record_compare("move", mark_record, move_record); +#endif +		} + +		/* If we ran into the end of the heap, then +		 * there's no need to keep walking +		 */ +		if (chunk_last != AO_LISP_NCHUNK) +			break; + +		/* Next loop starts right above this loop */ +		chunk_low = chunk_high; +	} + +#if DBG_MEM_STATS +	/* Collect stats */ +	++ao_lisp_collects[style]; +	ao_lisp_freed[style] += ao_lisp_top - top; +	ao_lisp_loops[style] += loops; +#endif + +	ao_lisp_top = top; +	if (style == AO_LISP_COLLECT_FULL) +		ao_lisp_last_top = top; + +	MDBG_DO(memset(ao_lisp_chunk, '\0', sizeof (ao_lisp_chunk)); +		walk(ao_lisp_mark_ref, ao_lisp_poly_mark_ref)); + +	return AO_LISP_POOL - ao_lisp_top; +} + +/* + * Mark interfaces for objects + */ + +/* + * Note a reference to memory and collect information about a few + * object sizes at a time + */ + +int +ao_lisp_mark_memory(const struct ao_lisp_type *type, void *addr) +{ +	int offset; +	if (!AO_LISP_IS_POOL(addr)) +		return 1; + +	offset = pool_offset(addr); +	MDBG_MOVE("mark memory %d\n", MDBG_OFFSET(addr)); +	if (busy(ao_lisp_busy, offset)) { +		MDBG_MOVE("already marked\n"); +		return 1; +	} +	mark(ao_lisp_busy, offset); +	note_chunk(offset, ao_lisp_size(type, addr)); +	return 0; +} + +/* + * Mark an object and all that it refereces + */ +int +ao_lisp_mark(const struct ao_lisp_type *type, void *addr) +{ +	int ret; +	MDBG_MOVE("mark %d\n", MDBG_OFFSET(addr)); +	MDBG_MOVE_IN(); +	ret = ao_lisp_mark_memory(type, addr); +	if (!ret) { +		MDBG_MOVE("mark recurse\n"); +		type->mark(addr); +	} +	MDBG_MOVE_OUT(); +	return ret; +} + +/* + * Mark an object, unless it is a cons cell and + * do_note_cons is set. In that case, just + * set a bit in the cons note array; those + * will be marked in a separate pass to avoid + * deep recursion in the collector + */ +int +ao_lisp_poly_mark(ao_poly p, uint8_t do_note_cons) +{ +	uint8_t type; +	void	*addr; + +	type = ao_lisp_poly_base_type(p); + +	if (type == AO_LISP_INT) +		return 1; + +	addr = ao_lisp_ref(p); +	if (!AO_LISP_IS_POOL(addr)) +		return 1; + +	if (type == AO_LISP_CONS && do_note_cons) { +		note_cons(pool_offset(addr)); +		return 1; +	} else { +		if (type == AO_LISP_OTHER) +			type = ao_lisp_other_type(addr); + +		const struct ao_lisp_type *lisp_type = ao_lisp_types[type]; +#if DBG_MEM +		if (!lisp_type) +			ao_lisp_abort(); +#endif + +		return ao_lisp_mark(lisp_type, addr); +	} +} + +/* + * Find the current location of an object + * based on the original location. For unmoved + * objects, this is simple. For moved objects, + * go search for it + */ + +static uint16_t +move_map(uint16_t offset) +{ +	int		l; + +	if (offset < chunk_low || chunk_high <= offset) +		return offset; + +	l = find_chunk(offset); + +#if DBG_MEM +	if (ao_lisp_chunk[l].old_offset != offset) +		ao_lisp_abort(); +#endif +	return ao_lisp_chunk[l].new_offset; +} + +int +ao_lisp_move_memory(const struct ao_lisp_type *type, void **ref) +{ +	void		*addr = *ref; +	uint16_t	offset, orig_offset; + +	if (!AO_LISP_IS_POOL(addr)) +		return 1; + +	(void) type; + +	MDBG_MOVE("move memory %d\n", MDBG_OFFSET(addr)); +	orig_offset = pool_offset(addr); +	offset = move_map(orig_offset); +	if (offset != orig_offset) { +		MDBG_MOVE("update ref %d %d -> %d\n", +			  AO_LISP_IS_POOL(ref) ? MDBG_OFFSET(ref) : -1, +			  orig_offset, offset); +		*ref = ao_lisp_pool + offset; +	} +	if (busy(ao_lisp_busy, offset)) { +		MDBG_MOVE("already moved\n"); +		return 1; +	} +	mark(ao_lisp_busy, offset); +	MDBG_DO(ao_lisp_record(type, addr, ao_lisp_size(type, addr))); +	return 0; +} + +int +ao_lisp_move(const struct ao_lisp_type *type, void **ref) +{ +	int ret; +	MDBG_MOVE("move object %d\n", MDBG_OFFSET(*ref)); +	MDBG_MOVE_IN(); +	ret = ao_lisp_move_memory(type, ref); +	if (!ret) { +		MDBG_MOVE("move recurse\n"); +		type->move(*ref); +	} +	MDBG_MOVE_OUT(); +	return ret; +} + +int +ao_lisp_poly_move(ao_poly *ref, uint8_t do_note_cons) +{ +	uint8_t		type; +	ao_poly		p = *ref; +	int		ret; +	void		*addr; +	uint16_t	offset, orig_offset; +	uint8_t		base_type; + +	base_type = type = ao_lisp_poly_base_type(p); + +	if (type == AO_LISP_INT) +		return 1; + +	addr = ao_lisp_ref(p); +	if (!AO_LISP_IS_POOL(addr)) +		return 1; + +	orig_offset = pool_offset(addr); +	offset = move_map(orig_offset); + +	if (type == AO_LISP_CONS && do_note_cons) { +		note_cons(orig_offset); +		ret = 1; +	} else { +		if (type == AO_LISP_OTHER) +			type = ao_lisp_other_type(ao_lisp_pool + offset); + +		const struct ao_lisp_type *lisp_type = ao_lisp_types[type]; +#if DBG_MEM +		if (!lisp_type) +			ao_lisp_abort(); +#endif + +		ret = ao_lisp_move(lisp_type, &addr); +	} + +	/* Re-write the poly value */ +	if (offset != orig_offset) { +		ao_poly np = ao_lisp_poly(ao_lisp_pool + offset, base_type); +		MDBG_MOVE("poly %d moved %d -> %d\n", +			  type, orig_offset, offset); +		*ref = np; +	} +	return ret; +} + +#if DBG_MEM +void +ao_lisp_validate(void) +{ +	chunk_low = 0; +	memset(ao_lisp_chunk, '\0', sizeof (ao_lisp_chunk)); +	walk(ao_lisp_mark_ref, ao_lisp_poly_mark_ref); +} + +int dbg_allocs; + +#endif + +void * +ao_lisp_alloc(int size) +{ +	void	*addr; + +	MDBG_DO(++dbg_allocs); +	MDBG_DO(if (dbg_validate) ao_lisp_validate()); +	size = ao_lisp_size_round(size); +	if (AO_LISP_POOL - ao_lisp_top < size && +	    ao_lisp_collect(AO_LISP_COLLECT_INCREMENTAL) < size && +	    ao_lisp_collect(AO_LISP_COLLECT_FULL) < size) +	{ +		ao_lisp_error(AO_LISP_OOM, "out of memory"); +		return NULL; +	} +	addr = ao_lisp_pool + ao_lisp_top; +	ao_lisp_top += size; +	return addr; +} + +void +ao_lisp_cons_stash(int id, struct ao_lisp_cons *cons) +{ +	save_cons[id] = cons; +} + +struct ao_lisp_cons * +ao_lisp_cons_fetch(int id) +{ +	struct ao_lisp_cons *cons = save_cons[id]; +	save_cons[id] = NULL; +	return cons; +} + +void +ao_lisp_poly_stash(int id, ao_poly poly) +{ +	save_poly[id] = poly; +} + +ao_poly +ao_lisp_poly_fetch(int id) +{ +	ao_poly poly = save_poly[id]; +	save_poly[id] = AO_LISP_NIL; +	return poly; +} + +void +ao_lisp_string_stash(int id, char *string) +{ +	save_string[id] = string; +} + +char * +ao_lisp_string_fetch(int id) +{ +	char *string = save_string[id]; +	save_string[id] = NULL; +	return string; +} + diff --git a/src/lisp/ao_lisp_os.h b/src/lisp/ao_lisp_os.h new file mode 100644 index 00000000..5fa3686b --- /dev/null +++ b/src/lisp/ao_lisp_os.h @@ -0,0 +1,53 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_LISP_OS_H_ +#define _AO_LISP_OS_H_ + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + +extern int ao_lisp_getc(void); + +static inline void +ao_lisp_os_flush(void) { +	fflush(stdout); +} + +static inline void +ao_lisp_abort(void) +{ +	abort(); +} + +static inline void +ao_lisp_os_led(int led) +{ +	printf("leds set to 0x%x\n", led); +} + +static inline void +ao_lisp_os_delay(int delay) +{ +	struct timespec ts = { +		.tv_sec = delay / 1000, +		.tv_nsec = (delay % 1000) * 1000000, +	}; +	nanosleep(&ts, NULL); +} +#endif diff --git a/src/lisp/ao_lisp_poly.c b/src/lisp/ao_lisp_poly.c new file mode 100644 index 00000000..fb3b06fe --- /dev/null +++ b/src/lisp/ao_lisp_poly.c @@ -0,0 +1,102 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" + +struct ao_lisp_funcs { +	void (*print)(ao_poly); +	void (*patom)(ao_poly); +}; + +static const struct ao_lisp_funcs ao_lisp_funcs[AO_LISP_NUM_TYPE] = { +	[AO_LISP_CONS] = { +		.print = ao_lisp_cons_print, +		.patom = ao_lisp_cons_patom, +	}, +	[AO_LISP_STRING] = { +		.print = ao_lisp_string_print, +		.patom = ao_lisp_string_patom, +	}, +	[AO_LISP_INT] = { +		.print = ao_lisp_int_print, +		.patom = ao_lisp_int_print, +	}, +	[AO_LISP_ATOM] = { +		.print = ao_lisp_atom_print, +		.patom = ao_lisp_atom_print, +	}, +	[AO_LISP_BUILTIN] = { +		.print = ao_lisp_builtin_print, +		.patom = ao_lisp_builtin_print, +	}, +	[AO_LISP_FRAME] = { +		.print = ao_lisp_frame_print, +		.patom = ao_lisp_frame_print, +	}, +	[AO_LISP_LAMBDA] = { +		.print = ao_lisp_lambda_print, +		.patom = ao_lisp_lambda_print, +	}, +	[AO_LISP_STACK] = { +		.print = ao_lisp_stack_print, +		.patom = ao_lisp_stack_print, +	}, +}; + +static const struct ao_lisp_funcs * +funcs(ao_poly p) +{ +	uint8_t	type = ao_lisp_poly_type(p); + +	if (type < AO_LISP_NUM_TYPE) +		return &ao_lisp_funcs[type]; +	return NULL; +} + +void +ao_lisp_poly_print(ao_poly p) +{ +	const struct ao_lisp_funcs *f = funcs(p); + +	if (f && f->print) +		f->print(p); +} + +void +ao_lisp_poly_patom(ao_poly p) +{ +	const struct ao_lisp_funcs *f = funcs(p); + +	if (f && f->patom) +		f->patom(p); +} + +void * +ao_lisp_ref(ao_poly poly) { +	if (poly == AO_LISP_NIL) +		return NULL; +	if (poly & AO_LISP_CONST) +		return (void *) (ao_lisp_const + (poly & AO_LISP_REF_MASK) - 4); +	return (void *) (ao_lisp_pool + (poly & AO_LISP_REF_MASK) - 4); +} + +ao_poly +ao_lisp_poly(const void *addr, ao_poly type) { +	const uint8_t	*a = addr; +	if (a == NULL) +		return AO_LISP_NIL; +	if (AO_LISP_IS_CONST(a)) +		return AO_LISP_CONST | (a - ao_lisp_const + 4) | type; +	return (a - ao_lisp_pool + 4) | type; +} diff --git a/src/lisp/ao_lisp_read.c b/src/lisp/ao_lisp_read.c new file mode 100644 index 00000000..84ef2a61 --- /dev/null +++ b/src/lisp/ao_lisp_read.c @@ -0,0 +1,498 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" +#include "ao_lisp_read.h" + +static const uint16_t	lex_classes[128] = { +	IGNORE,		/* ^@ */ +	IGNORE,		/* ^A */ +	IGNORE,		/* ^B */ +	IGNORE,		/* ^C */ +	IGNORE,		/* ^D */ +	IGNORE,		/* ^E */ +	IGNORE,		/* ^F */ +	IGNORE,		/* ^G */ +	IGNORE,		/* ^H */ +	WHITE,		/* ^I */ +	WHITE,		/* ^J */ +	WHITE,		/* ^K */ +	WHITE,		/* ^L */ +	WHITE,		/* ^M */ +	IGNORE,		/* ^N */ +	IGNORE,		/* ^O */ +	IGNORE,		/* ^P */ +	IGNORE,		/* ^Q */ +	IGNORE,		/* ^R */ +	IGNORE,		/* ^S */ +	IGNORE,		/* ^T */ +	IGNORE,		/* ^U */ +	IGNORE,		/* ^V */ +	IGNORE,		/* ^W */ +	IGNORE,		/* ^X */ +	IGNORE,		/* ^Y */ +	IGNORE,		/* ^Z */ +	IGNORE,		/* ^[ */ +	IGNORE,		/* ^\ */ +	IGNORE,		/* ^] */ +	IGNORE,		/* ^^ */ +	IGNORE,		/* ^_ */ +	PRINTABLE|WHITE,	/*    */ + 	PRINTABLE,		/* ! */ + 	PRINTABLE|STRINGC,	/* " */ + 	PRINTABLE|COMMENT,	/* # */ + 	PRINTABLE,		/* $ */ + 	PRINTABLE,		/* % */ + 	PRINTABLE,		/* & */ + 	PRINTABLE|QUOTEC,	/* ' */ + 	PRINTABLE|BRA,		/* ( */ + 	PRINTABLE|KET,		/* ) */ + 	PRINTABLE,		/* * */ + 	PRINTABLE|SIGN,		/* + */ + 	PRINTABLE,		/* , */ + 	PRINTABLE|SIGN,		/* - */ + 	PRINTABLE,		/* . */ + 	PRINTABLE,		/* / */ + 	PRINTABLE|DIGIT,	/* 0 */ + 	PRINTABLE|DIGIT,	/* 1 */ + 	PRINTABLE|DIGIT,	/* 2 */ + 	PRINTABLE|DIGIT,	/* 3 */ + 	PRINTABLE|DIGIT,	/* 4 */ + 	PRINTABLE|DIGIT,	/* 5 */ + 	PRINTABLE|DIGIT,	/* 6 */ + 	PRINTABLE|DIGIT,	/* 7 */ + 	PRINTABLE|DIGIT,	/* 8 */ + 	PRINTABLE|DIGIT,	/* 9 */ + 	PRINTABLE,		/* : */ + 	PRINTABLE|COMMENT,	/* ; */ + 	PRINTABLE,		/* < */ + 	PRINTABLE,		/* = */ + 	PRINTABLE,		/* > */ + 	PRINTABLE,		/* ? */ +  	PRINTABLE,		/*  @ */ +	PRINTABLE,		/*  A */ +	PRINTABLE,		/*  B */ +	PRINTABLE,		/*  C */ +	PRINTABLE,		/*  D */ +	PRINTABLE,		/*  E */ +	PRINTABLE,		/*  F */ +	PRINTABLE,		/*  G */ +	PRINTABLE,		/*  H */ +	PRINTABLE,		/*  I */ +	PRINTABLE,		/*  J */ +	PRINTABLE,		/*  K */ +	PRINTABLE,		/*  L */ +	PRINTABLE,		/*  M */ +	PRINTABLE,		/*  N */ +	PRINTABLE,		/*  O */ +	PRINTABLE,		/*  P */ +	PRINTABLE,		/*  Q */ +	PRINTABLE,		/*  R */ +	PRINTABLE,		/*  S */ +	PRINTABLE,		/*  T */ +	PRINTABLE,		/*  U */ +	PRINTABLE,		/*  V */ +	PRINTABLE,		/*  W */ +	PRINTABLE,		/*  X */ +	PRINTABLE,		/*  Y */ +	PRINTABLE,		/*  Z */ +	PRINTABLE,		/*  [ */ +	PRINTABLE|BACKSLASH,	/*  \ */ +	PRINTABLE,		/*  ] */ +	PRINTABLE,		/*  ^ */ +	PRINTABLE,		/*  _ */ +  	PRINTABLE,		/*  ` */ +	PRINTABLE,		/*  a */ +	PRINTABLE,		/*  b */ +	PRINTABLE,		/*  c */ +	PRINTABLE,		/*  d */ +	PRINTABLE,		/*  e */ +	PRINTABLE,		/*  f */ +	PRINTABLE,		/*  g */ +	PRINTABLE,		/*  h */ +	PRINTABLE,		/*  i */ +	PRINTABLE,		/*  j */ +	PRINTABLE,		/*  k */ +	PRINTABLE,		/*  l */ +	PRINTABLE,		/*  m */ +	PRINTABLE,		/*  n */ +	PRINTABLE,		/*  o */ +	PRINTABLE,		/*  p */ +	PRINTABLE,		/*  q */ +	PRINTABLE,		/*  r */ +	PRINTABLE,		/*  s */ +	PRINTABLE,		/*  t */ +	PRINTABLE,		/*  u */ +	PRINTABLE,		/*  v */ +	PRINTABLE,		/*  w */ +	PRINTABLE,		/*  x */ +	PRINTABLE,		/*  y */ +	PRINTABLE,		/*  z */ +	PRINTABLE,		/*  { */ +	PRINTABLE|VBAR,		/*  | */ +	PRINTABLE,		/*  } */ +	PRINTABLE|TWIDDLE,	/*  ~ */ +	IGNORE,			/*  ^? */ +}; + +static int lex_unget_c; + +static inline int +lex_get() +{ +	int	c; +	if (lex_unget_c) { +		c = lex_unget_c; +		lex_unget_c = 0; +	} else { +		c = ao_lisp_getc(); +	} +	return c; +} + +static inline void +lex_unget(int c) +{ +	if (c != EOF) +		lex_unget_c = c; +} + +static int +lex_quoted (void) +{ +	int	c; +	int	v; +	int	count; + +	c = lex_get(); +	if (c == EOF) +		return EOF; +	c &= 0x7f; + 	switch (c) { +	case 'n': +		return '\n'; +	case 'f': +		return '\f'; +	case 'b': +		return '\b'; +	case 'r': +		return '\r'; +	case 'v': +		return '\v'; +	case 't': +		return '\t'; +	case '0': +	case '1': +	case '2': +	case '3': +	case '4': +	case '5': +	case '6': +	case '7': +		v = c - '0'; +		count = 1; +		while (count <= 3) { +			c = lex_get(); +			if (c == EOF) +				return EOF; +			c &= 0x7f; +			if (c < '0' || '7' < c) { +				lex_unget(c); +				break; +			} +			v = (v << 3) + c - '0'; +			++count; +		} +		return v; +	default: +		return c; +	} +} + +static uint16_t	lex_class; + +static int +lexc(void) +{ +	int	c; +	do { +		c = lex_get(); +		if (c == EOF) { +			lex_class = ENDOFFILE; +			c = 0; +		} else { +			c &= 0x7f; +			lex_class = lex_classes[c]; +			if (lex_class & BACKSLASH) { +				c = lex_quoted(); +				if (c == EOF) +					lex_class = ENDOFFILE; +				else +					lex_class = PRINTABLE; +			} +		} +	} while (lex_class & IGNORE); +	return c; +} + +#define AO_LISP_TOKEN_MAX	32 + +static char	token_string[AO_LISP_TOKEN_MAX]; +static int	token_int; +static int	token_len; + +static inline void add_token(int c) { +	if (c && token_len < AO_LISP_TOKEN_MAX - 1) +		token_string[token_len++] = c; +} + +static inline void end_token(void) { +	token_string[token_len] = '\0'; +} + +static int +lex(void) +{ +	int	c; + +	token_len = 0; +	for (;;) { +		c = lexc(); +		if (lex_class & ENDOFFILE) +			return END; + +		if (lex_class & WHITE) +			continue; + +		if (lex_class & COMMENT) { +			while ((c = lexc()) != '\n') { +				if (lex_class & ENDOFFILE) +					return END; +			} +			continue; +		} + +		if (lex_class & (BRA|KET|QUOTEC)) { +			add_token(c); +			end_token(); +			switch (c) { +			case '(': +				return OPEN; +			case ')': +				return CLOSE; +			case '\'': +				return QUOTE; +			} +		} +		if (lex_class & TWIDDLE) { +			token_int = lexc(); +			return NUM; +		} +		if (lex_class & STRINGC) { +			for (;;) { +				c = lexc(); +				if (lex_class & (STRINGC|ENDOFFILE)) { +					end_token(); +					return STRING; +				} +				add_token(c); +			} +		} +		if (lex_class & PRINTABLE) { +			int	isnum; +			int	hasdigit; +			int	isneg; + +			isnum = 1; +			hasdigit = 0; +			token_int = 0; +			isneg = 0; +			for (;;) { +				if (!(lex_class & NUMBER)) { +					isnum = 0; +				} else { + 					if (token_len != 0 && +					    (lex_class & SIGN)) +					{ +						isnum = 0; +					} +					if (c == '-') +						isneg = 1; +					if (lex_class & DIGIT) { +						hasdigit = 1; +						if (isnum) +							token_int = token_int * 10 + c - '0'; +					} +				} +				add_token (c); +				c = lexc (); +				if (lex_class & (NOTNAME)) { +//					if (lex_class & ENDOFFILE) +//						clearerr (f); +					lex_unget(c); +					end_token (); +					if (isnum && hasdigit) { +						if (isneg) +							token_int = -token_int; +						return NUM; +					} +					return NAME; +				} +			} + +		} +	} +} + +static int parse_token; + +struct ao_lisp_cons	*ao_lisp_read_cons; +struct ao_lisp_cons	*ao_lisp_read_cons_tail; +struct ao_lisp_cons	*ao_lisp_read_stack; + +static int +push_read_stack(int cons, int in_quote) +{ +	DBGI("push read stack %p %d\n", ao_lisp_read_cons, in_quote); +	DBG_IN(); +	if (cons) { +		ao_lisp_read_stack = ao_lisp_cons_cons(ao_lisp_cons_poly(ao_lisp_read_cons), +					       ao_lisp_cons_cons(ao_lisp_int_poly(in_quote), +								 ao_lisp_read_stack)); +		if (!ao_lisp_read_stack) +			return 0; +	} +	ao_lisp_read_cons = NULL; +	ao_lisp_read_cons_tail = NULL; +	return 1; +} + +static int +pop_read_stack(int cons) +{ +	int	in_quote = 0; +	if (cons) { +		ao_lisp_read_cons = ao_lisp_poly_cons(ao_lisp_read_stack->car); +		ao_lisp_read_stack = ao_lisp_poly_cons(ao_lisp_read_stack->cdr); +		in_quote = ao_lisp_poly_int(ao_lisp_read_stack->car); +		ao_lisp_read_stack = ao_lisp_poly_cons(ao_lisp_read_stack->cdr); +		for (ao_lisp_read_cons_tail = ao_lisp_read_cons; +		     ao_lisp_read_cons_tail && ao_lisp_read_cons_tail->cdr; +		     ao_lisp_read_cons_tail = ao_lisp_poly_cons(ao_lisp_read_cons_tail->cdr)) +			; +	} else { +		ao_lisp_read_cons = 0; +		ao_lisp_read_cons_tail = 0; +		ao_lisp_read_stack = 0; +	} +	DBG_OUT(); +	DBGI("pop read stack %p %d\n", ao_lisp_read_cons, in_quote); +	return in_quote; +} + +ao_poly +ao_lisp_read(void) +{ +	struct ao_lisp_atom	*atom; +	char			*string; +	int			cons; +	int			in_quote; +	ao_poly			v; + +	parse_token = lex(); +	DBGI("token %d (%s)\n", parse_token, token_string); + +	cons = 0; +	in_quote = 0; +	ao_lisp_read_cons = ao_lisp_read_cons_tail = ao_lisp_read_stack = 0; +	for (;;) { +		while (parse_token == OPEN) { +			if (!push_read_stack(cons, in_quote)) +				return AO_LISP_NIL; +			cons++; +			in_quote = 0; +			parse_token = lex(); +			DBGI("token %d (%s)\n", parse_token, token_string); +		} + +		switch (parse_token) { +		case END: +		default: +			if (cons) +				ao_lisp_error(AO_LISP_EOF, "unexpected end of file"); +			return _ao_lisp_atom_eof; +			break; +		case NAME: +			atom = ao_lisp_atom_intern(token_string); +			if (atom) +				v = ao_lisp_atom_poly(atom); +			else +				v = AO_LISP_NIL; +			break; +		case NUM: +			v = ao_lisp_int_poly(token_int); +			break; +		case STRING: +			string = ao_lisp_string_copy(token_string); +			if (string) +				v = ao_lisp_string_poly(string); +			else +				v = AO_LISP_NIL; +			break; +		case QUOTE: +			if (!push_read_stack(cons, in_quote)) +				return AO_LISP_NIL; +			cons++; +			in_quote = 1; +			v = _ao_lisp_atom_quote; +			break; +		case CLOSE: +			if (!cons) { +				v = AO_LISP_NIL; +				break; +			} +			v = ao_lisp_cons_poly(ao_lisp_read_cons); +			--cons; +			in_quote = pop_read_stack(cons); +			break; +		} + +		/* loop over QUOTE ends */ +		for (;;) { +			if (!cons) +				return v; + +			struct ao_lisp_cons	*read = ao_lisp_cons_cons(v, NULL); +			if (!read) +				return AO_LISP_NIL; + +			if (ao_lisp_read_cons_tail) +				ao_lisp_read_cons_tail->cdr = ao_lisp_cons_poly(read); +			else +				ao_lisp_read_cons = read; +			ao_lisp_read_cons_tail = read; + +			if (!in_quote || !ao_lisp_read_cons->cdr) +				break; + +			v = ao_lisp_cons_poly(ao_lisp_read_cons); +			--cons; +			in_quote = pop_read_stack(cons); +		} + +		parse_token = lex(); +		DBGI("token %d (%s)\n", parse_token, token_string); +	} +	return v; +} diff --git a/src/lisp/ao_lisp_read.h b/src/lisp/ao_lisp_read.h new file mode 100644 index 00000000..1c994d56 --- /dev/null +++ b/src/lisp/ao_lisp_read.h @@ -0,0 +1,49 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef _AO_LISP_READ_H_ +#define _AO_LISP_READ_H_ + +# define END	0 +# define NAME	1 +# define OPEN  	2 +# define CLOSE	3 +# define QUOTE	4 +# define STRING	5 +# define NUM	6 + +/* + * character classes + */ + +# define PRINTABLE	0x00000001	/* \t \n ' ' - '~' */ +# define QUOTED		0x00000002	/* \ anything */ +# define BRA		0x00000004	/* ( [ { */ +# define KET		0x00000008	/* ) ] } */ +# define WHITE		0x00000010	/* ' ' \t \n */ +# define DIGIT		0x00000020	/* [0-9] */ +# define SIGN		0x00000040	/* +- */ +# define ENDOFFILE	0x00000080	/* end of file */ +# define COMMENT	0x00000100	/* ; # */ +# define IGNORE		0x00000200	/* \0 - ' ' */ +# define QUOTEC		0x00000400	/* ' */ +# define BACKSLASH	0x00000800	/* \ */ +# define VBAR		0x00001000	/* | */ +# define TWIDDLE	0x00002000	/* ~ */ +# define STRINGC	0x00004000	/* " */ + +# define NOTNAME	(STRINGC|TWIDDLE|VBAR|QUOTEC|COMMENT|ENDOFFILE|WHITE|KET|BRA) +# define NUMBER		(DIGIT|SIGN) + +#endif /* _AO_LISP_READ_H_ */ diff --git a/src/lisp/ao_lisp_rep.c b/src/lisp/ao_lisp_rep.c new file mode 100644 index 00000000..3be95d44 --- /dev/null +++ b/src/lisp/ao_lisp_rep.c @@ -0,0 +1,34 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" + +ao_poly +ao_lisp_read_eval_print(void) +{ +	ao_poly	in, out = AO_LISP_NIL; +	for(;;) { +		in = ao_lisp_read(); +		if (in == _ao_lisp_atom_eof || in == AO_LISP_NIL) +			break; +		out = ao_lisp_eval(in); +		if (ao_lisp_exception) { +			ao_lisp_exception = 0; +		} else { +			ao_lisp_poly_print(out); +			putchar ('\n'); +		} +	} +	return out; +} diff --git a/src/lisp/ao_lisp_save.c b/src/lisp/ao_lisp_save.c new file mode 100644 index 00000000..4f850fb9 --- /dev/null +++ b/src/lisp/ao_lisp_save.c @@ -0,0 +1,76 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <ao_lisp.h> + +ao_poly +ao_lisp_save(struct ao_lisp_cons *cons) +{ +	if (!ao_lisp_check_argc(_ao_lisp_atom_save, cons, 0, 0)) +		return AO_LISP_NIL; + +#ifdef AO_LISP_SAVE +	struct ao_lisp_os_save *os = (struct ao_lisp_os_save *) (void *) &ao_lisp_pool[AO_LISP_POOL]; + +	ao_lisp_collect(AO_LISP_COLLECT_FULL); +	os->atoms = ao_lisp_atom_poly(ao_lisp_atoms); +	os->globals = ao_lisp_frame_poly(ao_lisp_frame_global); +	os->const_checksum = ao_lisp_const_checksum; +	os->const_checksum_inv = (uint16_t) ~ao_lisp_const_checksum; + +	if (ao_lisp_os_save()) +		return _ao_lisp_atom_t; +#endif +	return AO_LISP_NIL; +} + +ao_poly +ao_lisp_restore(struct ao_lisp_cons *cons) +{ +	if (!ao_lisp_check_argc(_ao_lisp_atom_save, cons, 0, 0)) +		return AO_LISP_NIL; + +#ifdef AO_LISP_SAVE +	struct ao_lisp_os_save save; +	struct ao_lisp_os_save *os = (struct ao_lisp_os_save *) (void *) &ao_lisp_pool[AO_LISP_POOL]; + +	if (!ao_lisp_os_restore_save(&save, AO_LISP_POOL)) +		return ao_lisp_error(AO_LISP_INVALID, "header restore failed"); + +	if (save.const_checksum != ao_lisp_const_checksum || +	    save.const_checksum_inv != (uint16_t) ~ao_lisp_const_checksum) +	{ +		return ao_lisp_error(AO_LISP_INVALID, "image is corrupted or stale"); +	} + +	if (ao_lisp_os_restore()) { + +		ao_lisp_atoms = ao_lisp_poly_atom(os->atoms); +		ao_lisp_frame_global = ao_lisp_poly_frame(os->globals); + +		/* Clear the eval global variabls */ +		ao_lisp_eval_clear_globals(); + +		/* Reset the allocator */ +		ao_lisp_top = AO_LISP_POOL; +		ao_lisp_collect(AO_LISP_COLLECT_FULL); + +		/* Re-create the evaluator stack */ +		if (!ao_lisp_eval_restart()) +			return AO_LISP_NIL; +		return _ao_lisp_atom_t; +	} +#endif +	return AO_LISP_NIL; +} diff --git a/src/lisp/ao_lisp_stack.c b/src/lisp/ao_lisp_stack.c new file mode 100644 index 00000000..53adf432 --- /dev/null +++ b/src/lisp/ao_lisp_stack.c @@ -0,0 +1,278 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" + +const struct ao_lisp_type ao_lisp_stack_type; + +static int +stack_size(void *addr) +{ +	(void) addr; +	return sizeof (struct ao_lisp_stack); +} + +static void +stack_mark(void *addr) +{ +	struct ao_lisp_stack	*stack = addr; +	for (;;) { +		ao_lisp_poly_mark(stack->sexprs, 0); +		ao_lisp_poly_mark(stack->values, 0); +		/* no need to mark values_tail */ +		ao_lisp_poly_mark(stack->frame, 0); +		ao_lisp_poly_mark(stack->list, 0); +		stack = ao_lisp_poly_stack(stack->prev); +		if (ao_lisp_mark_memory(&ao_lisp_stack_type, stack)) +			break; +	} +} + +static void +stack_move(void *addr) +{ +	struct ao_lisp_stack	*stack = addr; + +	while (stack) { +		struct ao_lisp_stack	*prev; +		int			ret; +		(void) ao_lisp_poly_move(&stack->sexprs, 0); +		(void) ao_lisp_poly_move(&stack->values, 0); +		(void) ao_lisp_poly_move(&stack->values_tail, 0); +		(void) ao_lisp_poly_move(&stack->frame, 0); +		(void) ao_lisp_poly_move(&stack->list, 0); +		prev = ao_lisp_poly_stack(stack->prev); +		if (!prev) +			break; +		ret = ao_lisp_move_memory(&ao_lisp_stack_type, (void **) &prev); +		if (prev != ao_lisp_poly_stack(stack->prev)) +			stack->prev = ao_lisp_stack_poly(prev); +		if (ret) +			break; +		stack = prev; +	} +} + +const struct ao_lisp_type ao_lisp_stack_type = { +	.size = stack_size, +	.mark = stack_mark, +	.move = stack_move, +	.name = "stack" +}; + +struct ao_lisp_stack		*ao_lisp_stack_free_list; + +void +ao_lisp_stack_reset(struct ao_lisp_stack *stack) +{ +	stack->state = eval_sexpr; +	stack->sexprs = AO_LISP_NIL; +	stack->values = AO_LISP_NIL; +	stack->values_tail = AO_LISP_NIL; +} + +static struct ao_lisp_stack * +ao_lisp_stack_new(void) +{ +	struct ao_lisp_stack *stack; + +	if (ao_lisp_stack_free_list) { +		stack = ao_lisp_stack_free_list; +		ao_lisp_stack_free_list = ao_lisp_poly_stack(stack->prev); +	} else { +		stack = ao_lisp_alloc(sizeof (struct ao_lisp_stack)); +		if (!stack) +			return 0; +		stack->type = AO_LISP_STACK; +	} +	ao_lisp_stack_reset(stack); +	return stack; +} + +int +ao_lisp_stack_push(void) +{ +	struct ao_lisp_stack	*stack = ao_lisp_stack_new(); + +	if (!stack) +		return 0; + +	stack->prev = ao_lisp_stack_poly(ao_lisp_stack); +	stack->frame = ao_lisp_frame_poly(ao_lisp_frame_current); +	stack->list = AO_LISP_NIL; + +	ao_lisp_stack = stack; + +	DBGI("stack push\n"); +	DBG_FRAMES(); +	DBG_IN(); +	return 1; +} + +void +ao_lisp_stack_pop(void) +{ +	ao_poly			prev; +	struct ao_lisp_frame	*prev_frame; + +	if (!ao_lisp_stack) +		return; +	prev = ao_lisp_stack->prev; +	if (!ao_lisp_stack_marked(ao_lisp_stack)) { +		ao_lisp_stack->prev = ao_lisp_stack_poly(ao_lisp_stack_free_list); +		ao_lisp_stack_free_list = ao_lisp_stack; +	} + +	ao_lisp_stack = ao_lisp_poly_stack(prev); +	prev_frame = ao_lisp_frame_current; +	if (ao_lisp_stack) +		ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->frame); +	else +		ao_lisp_frame_current = NULL; +	if (ao_lisp_frame_current != prev_frame) +		ao_lisp_frame_free(prev_frame); +	DBG_OUT(); +	DBGI("stack pop\n"); +	DBG_FRAMES(); +} + +void +ao_lisp_stack_clear(void) +{ +	ao_lisp_stack = NULL; +	ao_lisp_frame_current = NULL; +	ao_lisp_v = AO_LISP_NIL; +} + +void +ao_lisp_stack_print(ao_poly poly) +{ +	struct ao_lisp_stack *s = ao_lisp_poly_stack(poly); + +	while (s) { +		if (s->type & AO_LISP_STACK_PRINT) { +			printf("[recurse...]"); +			return; +		} +		s->type |= AO_LISP_STACK_PRINT; +		printf("\t[\n"); +		printf("\t\texpr:   "); ao_lisp_poly_print(s->list); printf("\n"); +		printf("\t\tstate:  %s\n", ao_lisp_state_names[s->state]); +		ao_lisp_error_poly ("values: ", s->values, s->values_tail); +		ao_lisp_error_poly ("sexprs: ", s->sexprs, AO_LISP_NIL); +		ao_lisp_error_frame(2, "frame:  ", ao_lisp_poly_frame(s->frame)); +		printf("\t]\n"); +		s->type &= ~AO_LISP_STACK_PRINT; +		s = ao_lisp_poly_stack(s->prev); +	} +} + +/* + * Copy a stack, being careful to keep everybody referenced + */ +static struct ao_lisp_stack * +ao_lisp_stack_copy(struct ao_lisp_stack *old) +{ +	struct ao_lisp_stack *new = NULL; +	struct ao_lisp_stack *n, *prev = NULL; + +	while (old) { +		ao_lisp_stack_stash(0, old); +		ao_lisp_stack_stash(1, new); +		ao_lisp_stack_stash(2, prev); +		n = ao_lisp_stack_new(); +		prev = ao_lisp_stack_fetch(2); +		new = ao_lisp_stack_fetch(1); +		old = ao_lisp_stack_fetch(0); +		if (!n) +			return NULL; + +		ao_lisp_stack_mark(old); +		ao_lisp_frame_mark(ao_lisp_poly_frame(old->frame)); +		*n = *old; + +		if (prev) +			prev->prev = ao_lisp_stack_poly(n); +		else +			new = n; +		prev = n; + +		old = ao_lisp_poly_stack(old->prev); +	} +	return new; +} + +/* + * Evaluate a continuation invocation + */ +ao_poly +ao_lisp_stack_eval(void) +{ +	struct ao_lisp_stack	*new = ao_lisp_stack_copy(ao_lisp_poly_stack(ao_lisp_v)); +	if (!new) +		return AO_LISP_NIL; + +	struct ao_lisp_cons	*cons = ao_lisp_poly_cons(ao_lisp_stack->values); + +	if (!cons || !cons->cdr) +		return ao_lisp_error(AO_LISP_INVALID, "continuation requires a value"); + +	new->state = eval_val; + +	ao_lisp_stack = new; +	ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->frame); + +	return ao_lisp_poly_cons(cons->cdr)->car; +} + +/* + * Call with current continuation. This calls a lambda, passing + * it a single argument which is the current continuation + */ +ao_poly +ao_lisp_call_cc(struct ao_lisp_cons *cons) +{ +	struct ao_lisp_stack	*new; +	ao_poly			v; + +	/* Make sure the single parameter is a lambda */ +	if (!ao_lisp_check_argc(_ao_lisp_atom_call2fcc, cons, 1, 1)) +		return AO_LISP_NIL; +	if (!ao_lisp_check_argt(_ao_lisp_atom_call2fcc, cons, 0, AO_LISP_LAMBDA, 0)) +		return AO_LISP_NIL; + +	/* go get the lambda */ +	ao_lisp_v = ao_lisp_arg(cons, 0); + +	/* Note that the whole call chain now has +	 * a reference to it which may escape +	 */ +	new = ao_lisp_stack_copy(ao_lisp_stack); +	if (!new) +		return AO_LISP_NIL; + +	/* re-fetch cons after the allocation */ +	cons = ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->values)->cdr); + +	/* Reset the arg list to the current stack, +	 * and call the lambda +	 */ + +	cons->car = ao_lisp_stack_poly(new); +	cons->cdr = AO_LISP_NIL; +	v = ao_lisp_lambda_eval(); +	ao_lisp_stack->sexprs = v; +	ao_lisp_stack->state = eval_progn; +	return AO_LISP_NIL; +} diff --git a/src/lisp/ao_lisp_string.c b/src/lisp/ao_lisp_string.c new file mode 100644 index 00000000..cd7b27a9 --- /dev/null +++ b/src/lisp/ao_lisp_string.c @@ -0,0 +1,158 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao_lisp.h" + +static void string_mark(void *addr) +{ +	(void) addr; +} + +static int string_size(void *addr) +{ +	if (!addr) +		return 0; +	return strlen(addr) + 1; +} + +static void string_move(void *addr) +{ +	(void) addr; +} + +const struct ao_lisp_type ao_lisp_string_type = { +	.mark = string_mark, +	.size = string_size, +	.move = string_move, +	.name = "string", +}; + +char * +ao_lisp_string_copy(char *a) +{ +	int	alen = strlen(a); + +	ao_lisp_string_stash(0, a); +	char	*r = ao_lisp_alloc(alen + 1); +	a = ao_lisp_string_fetch(0); +	if (!r) +		return NULL; +	strcpy(r, a); +	return r; +} + +char * +ao_lisp_string_cat(char *a, char *b) +{ +	int	alen = strlen(a); +	int	blen = strlen(b); + +	ao_lisp_string_stash(0, a); +	ao_lisp_string_stash(1, b); +	char	*r = ao_lisp_alloc(alen + blen + 1); +	a = ao_lisp_string_fetch(0); +	b = ao_lisp_string_fetch(1); +	if (!r) +		return NULL; +	strcpy(r, a); +	strcpy(r+alen, b); +	return r; +} + +ao_poly +ao_lisp_string_pack(struct ao_lisp_cons *cons) +{ +	int	len = ao_lisp_cons_length(cons); +	ao_lisp_cons_stash(0, cons); +	char	*r = ao_lisp_alloc(len + 1); +	cons = ao_lisp_cons_fetch(0); +	char	*s = r; + +	while (cons) { +		if (ao_lisp_poly_type(cons->car) != AO_LISP_INT) +			return ao_lisp_error(AO_LISP_INVALID, "non-int passed to pack"); +		*s++ = ao_lisp_poly_int(cons->car); +		cons = ao_lisp_poly_cons(cons->cdr); +	} +	*s++ = 0; +	return ao_lisp_string_poly(r); +} + +ao_poly +ao_lisp_string_unpack(char *a) +{ +	struct ao_lisp_cons	*cons = NULL, *tail = NULL; +	int			c; +	int			i; + +	for (i = 0; (c = a[i]); i++) { +		ao_lisp_cons_stash(0, cons); +		ao_lisp_cons_stash(1, tail); +		ao_lisp_string_stash(0, a); +		struct ao_lisp_cons	*n = ao_lisp_cons_cons(ao_lisp_int_poly(c), NULL); +		a = ao_lisp_string_fetch(0); +		cons = ao_lisp_cons_fetch(0); +		tail = ao_lisp_cons_fetch(1); + +		if (!n) { +			cons = NULL; +			break; +		} +		if (tail) +			tail->cdr = ao_lisp_cons_poly(n); +		else +			cons = n; +		tail = n; +	} +	return ao_lisp_cons_poly(cons); +} + +void +ao_lisp_string_print(ao_poly p) +{ +	char	*s = ao_lisp_poly_string(p); +	char	c; + +	putchar('"'); +	while ((c = *s++)) { +		switch (c) { +		case '\n': +			printf ("\\n"); +			break; +		case '\r': +			printf ("\\r"); +			break; +		case '\t': +			printf ("\\t"); +			break; +		default: +			putchar(c); +			break; +		} +	} +	putchar('"'); +} + +void +ao_lisp_string_patom(ao_poly p) +{ +	char	*s = ao_lisp_poly_string(p); +	char	c; + +	while ((c = *s++)) +		putchar(c); +} diff --git a/src/lpc/Makefile-lpc.defs b/src/lpc/Makefile-lpc.defs index bccea5bc..c4521620 100644 --- a/src/lpc/Makefile-lpc.defs +++ b/src/lpc/Makefile-lpc.defs @@ -4,7 +4,7 @@ endif  include $(TOPDIR)/Makedefs -vpath % $(TOPDIR)/lpc:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR/aes):$(TOPDIR):$(TOPDIR)/math +vpath % $(TOPDIR)/lpc:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR)/aes:$(TOPDIR):$(TOPDIR)/math  vpath make-altitude $(TOPDIR)/util  vpath make-kalman $(TOPDIR)/util  vpath kalman.5c $(TOPDIR)/kalman @@ -26,9 +26,12 @@ endif  ELFTOHEX=$(TOPDIR)/../ao-tools/ao-elftohex/ao-elftohex  CC=$(ARM_CC) -WARN_FLAGS=-Wall -Wextra -Werror +WARN_FLAGS=-Wall -Wextra -Werror -Wcast-align + +AO_CFLAGS=-I. -I$(TOPDIR)/lpc -I$(TOPDIR)/kernel -I$(TOPDIR)/drivers \ +	-I$(TOPDIR)/product -I$(TOPDIR) -I$(TOPDIR)/math -I$(TOPDIR) \ +	$(PDCLIB_INCLUDES)  -AO_CFLAGS=-I. -I$(TOPDIR)/lpc -I$(TOPDIR)/kernel -I$(TOPDIR)/drivers -I$(TOPDIR)/product -I$(TOPDIR) -I$(TOPDIR)/math -I$(TOPDIR) $(PDCLIB_INCLUDES)   LPC_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m0 -mthumb\  	-ffreestanding -nostdlib $(AO_CFLAGS) $(WARN_FLAGS) diff --git a/src/lpc/ao_arch_funcs.h b/src/lpc/ao_arch_funcs.h index 5fc0f680..15106dea 100644 --- a/src/lpc/ao_arch_funcs.h +++ b/src/lpc/ao_arch_funcs.h @@ -109,7 +109,7 @@ ao_arch_memory_barrier() {  static inline void  ao_arch_init_stack(struct ao_task *task, void *start)  { -	uint32_t	*sp = (uint32_t *) (task->stack + AO_STACK_SIZE); +	uint32_t	*sp = (uint32_t *) (void *) (task->stack + AO_STACK_SIZE);  	uint32_t	a = (uint32_t) start;  	int		i; diff --git a/src/nucleao-32/.gitignore b/src/nucleao-32/.gitignore new file mode 100644 index 00000000..cb8f78e5 --- /dev/null +++ b/src/nucleao-32/.gitignore @@ -0,0 +1,2 @@ +ao_product.h +nucleo-32* diff --git a/src/nucleao-32/Makefile b/src/nucleao-32/Makefile new file mode 100644 index 00000000..69049982 --- /dev/null +++ b/src/nucleao-32/Makefile @@ -0,0 +1,93 @@ +# +# AltOS build +# +# + +include ../stmf0/Makefile.defs + +INC = \ +	ao.h \ +	ao_arch.h \ +	ao_arch_funcs.h \ +	ao_boot.h \ +	ao_pins.h \ +	ao_product.h \ +	ao_task.h \ +	ao_lisp.h \ +	ao_lisp_const.h \ +	stm32f0.h \ +	Makefile + +ALTOS_SRC = \ +	ao_boot_chain.c \ +	ao_interrupt.c \ +	ao_product.c \ +	ao_romconfig.c \ +	ao_cmd.c \ +	ao_config.c \ +	ao_task.c \ +	ao_led.c \ +	ao_beep_stm.c \ +	ao_dma_stm.c \ +	ao_stdio.c \ +	ao_panic.c \ +	ao_timer.c \ +	ao_mutex.c \ +	ao_usb_stm.c \ +	ao_serial_stm.c \ +	ao_flash_stm.c \ +	ao_lisp_atom.c \ +	ao_lisp_builtin.c \ +	ao_lisp_cons.c \ +	ao_lisp_error.c \ +	ao_lisp_eval.c \ +	ao_lisp_frame.c \ +	ao_lisp_int.c \ +	ao_lisp_lambda.c \ +	ao_lisp_lex.c \ +	ao_lisp_mem.c \ +	ao_lisp_poly.c \ +	ao_lisp_read.c \ +	ao_lisp_rep.c \ +	ao_lisp_save.c \ +	ao_lisp_stack.c \ +	ao_lisp_string.c \ +	ao_lisp_os_save.c + +PRODUCT=Nucleo-32 +PRODUCT_DEF=-DNUCLEO +IDPRODUCT=0x000a + +CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -Os -g + +LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Tload.ld + +PROGNAME=nucleo-32 +PROG=$(PROGNAME)-$(VERSION).elf +HEX=$(PROGNAME)-$(VERSION).ihx + +SRC=$(ALTOS_SRC) ao_nucleo.c +OBJ=$(SRC:.c=.o) + +all: $(PROG) $(HEX) + +$(PROG): Makefile $(OBJ) altos.ld +	$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) + +$(OBJ): $(INC) + +ao_product.h: ao-make-product.5c ../Version +	$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +load: $(PROG) +	stm-load $(PROG) + +distclean:	clean + +clean: +	rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx +	rm -f ao_product.h + +install: + +uninstall: diff --git a/src/nucleao-32/ao_nucleo.c b/src/nucleao-32/ao_nucleo.c new file mode 100644 index 00000000..6b4cbaae --- /dev/null +++ b/src/nucleao-32/ao_nucleo.c @@ -0,0 +1,48 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <ao.h> +#include <ao_lisp.h> +#include <ao_beep.h> + +static void lisp_cmd() { +	ao_lisp_read_eval_print(); +} + +static void beep() { +	ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200)); +} + +static const struct ao_cmds blink_cmds[] = { +	{ lisp_cmd,	"l\0Run lisp interpreter" }, +	{ beep,		"b\0Beep" }, +	{ 0, 0 } +}; + +void main(void) +{ +	ao_led_init(LEDS_AVAILABLE); +	ao_clock_init(); +	ao_task_init(); +	ao_timer_init(); +	ao_dma_init(); +	ao_usb_init(); +	ao_serial_init(); +	ao_beep_init(); +	ao_cmd_init(); +	ao_cmd_register(blink_cmds); +	ao_start_scheduler(); +} + + diff --git a/src/nucleao-32/ao_pins.h b/src/nucleao-32/ao_pins.h new file mode 100644 index 00000000..cee4616f --- /dev/null +++ b/src/nucleao-32/ao_pins.h @@ -0,0 +1,65 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#define LED_PORT_ENABLE	STM_RCC_AHBENR_IOPBEN +#define LED_PORT	(&stm_gpiob) +#define LED_PIN_GREEN	3 +#define AO_LED_GREEN	(1 << LED_PIN_GREEN) +#define AO_LED_PANIC	AO_LED_GREEN +#define AO_CMD_LEN	128 +#define AO_LISP_POOL_TOTAL	3072 +#define AO_LISP_SAVE	1 +#define AO_STACK_SIZE	1024 + +#define LEDS_AVAILABLE	(AO_LED_GREEN) + +#define AO_POWER_MANAGEMENT	0 + +/* 48MHz clock based on USB */ +#define AO_HSI48	1 + +/* HCLK = 48MHz */ +#define AO_AHB_PRESCALER	1 +#define AO_RCC_CFGR_HPRE_DIV	STM_RCC_CFGR_HPRE_DIV_1 + +/* APB = 48MHz */ +#define AO_APB_PRESCALER	1 +#define AO_RCC_CFGR_PPRE_DIV	STM_RCC_CFGR_PPRE_DIV_1 + +#define HAS_USB				1 +#define AO_USB_DIRECTIO			0 +#define AO_PA11_PA12_RMP		0 +#define HAS_BEEP			1 + +#define BEEPER_TIMER			2 +#define BEEPER_CHANNEL			4 +#define BEEPER_PORT			(&stm_gpioa) +#define BEEPER_PIN			3 + +#define IS_FLASH_LOADER	0 + +#define HAS_SERIAL_2		1 +#define SERIAL_2_PA2_PA15	1 +#define USE_SERIAL_2_FLOW	0 +#define USE_SERIAL_2_STDIN	1 +#define DELAY_SERIAL_2_STDIN	0 + +#endif /* _AO_PINS_H_ */ diff --git a/src/nucleao-32/flash-loader/.gitignore b/src/nucleao-32/flash-loader/.gitignore new file mode 100644 index 00000000..cb8f78e5 --- /dev/null +++ b/src/nucleao-32/flash-loader/.gitignore @@ -0,0 +1,2 @@ +ao_product.h +nucleo-32* diff --git a/src/nucleao-32/flash-loader/Makefile b/src/nucleao-32/flash-loader/Makefile new file mode 100644 index 00000000..2392e998 --- /dev/null +++ b/src/nucleao-32/flash-loader/Makefile @@ -0,0 +1,8 @@ +# +# AltOS flash loader build +# +# + +TOPDIR=../.. +HARDWARE=nucleo-32 +include $(TOPDIR)/stmf0/Makefile-flash.defs diff --git a/src/nucleao-32/flash-loader/ao_pins.h b/src/nucleao-32/flash-loader/ao_pins.h new file mode 100644 index 00000000..8bdbdb1a --- /dev/null +++ b/src/nucleao-32/flash-loader/ao_pins.h @@ -0,0 +1,37 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#include <ao_flash_stm_pins.h> + +/* Pin D3, which is PB0 */ + +#define AO_BOOT_PIN			1 +#define AO_BOOT_APPLICATION_GPIO	stm_gpiob +#define AO_BOOT_APPLICATION_PIN		0 +#define AO_BOOT_APPLICATION_VALUE	1 +#define AO_BOOT_APPLICATION_MODE	AO_EXTI_MODE_PULL_UP + +/* USB */ +#define HAS_USB			1 +#define AO_USB_DIRECTIO		0 +#define AO_PA11_PA12_RMP	0 + +#endif /* _AO_PINS_H_ */ diff --git a/src/pnpservo-v1/Makefile b/src/pnpservo-v1/Makefile new file mode 100644 index 00000000..8606b1ae --- /dev/null +++ b/src/pnpservo-v1/Makefile @@ -0,0 +1,72 @@ +# +# AltOS build +# +# + +include ../stmf0/Makefile.defs + +INC = \ +	ao.h \ +	ao_arch.h \ +	ao_arch_funcs.h \ +	ao_boot.h \ +	ao_pins.h \ +	ao_product.h \ +	ao_task.h \ +	stm32f0.h \ +	Makefile + +ALTOS_SRC = \ +	ao_boot_chain.c \ +	ao_interrupt.c \ +	ao_product.c \ +	ao_romconfig.c \ +	ao_cmd.c \ +	ao_config.c \ +	ao_task.c \ +	ao_led.c \ +	ao_dma_stm.c \ +	ao_stdio.c \ +	ao_mutex.c \ +	ao_panic.c \ +	ao_timer.c \ +	ao_usb_stm.c \ +	ao_flash_stm.c  + +PRODUCT=PNPservo-v1 +PRODUCT_DEF=-DPNPSERVO +IDPRODUCT=0x000a + +CFLAGS = $(PRODUCT_DEF) -I. $(STMF0_CFLAGS) -Os -g + +LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Tlambda.ld + +PROGNAME=pnpservo-v1 +PROG=$(PROGNAME)-$(VERSION).elf +HEX=$(PROGNAME)-$(VERSION).ihx + +SRC=$(ALTOS_SRC) ao_pnpservo.c +OBJ=$(SRC:.c=.o) + +all: $(PROG) $(HEX) + +$(PROG): Makefile $(OBJ) lambda.ld altos.ld +	$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) + +$(OBJ): $(INC) + +ao_product.h: ao-make-product.5c ../Version +	$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +load: $(PROG) +	stm-load $(PROG) + +distclean:	clean + +clean: +	rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx +	rm -f ao_product.h + +install: + +uninstall: diff --git a/src/pnpservo-v1/ao_pins.h b/src/pnpservo-v1/ao_pins.h new file mode 100644 index 00000000..38f3d8e5 --- /dev/null +++ b/src/pnpservo-v1/ao_pins.h @@ -0,0 +1,59 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#define LED_PORT_ENABLE	STM_RCC_AHBENR_IOPAEN +#define LED_PORT	(&stm_gpioa) +#define LED_PIN_RED	9 +#define LED_PIN_GREEN	10 +#define AO_LED_RED	(1 << LED_PIN_RED) +#define AO_LED_GREEN	(1 << LED_PIN_GREEN) +#define AO_LED_PANIC	AO_LED_RED +#define AO_CMD_LEN	128 +#define AO_LISP_POOL_TOTAL	3072 +#define AO_LISP_SAVE	1 +#define AO_STACK_SIZE	1024 + +/* need HSI active to write to flash */ +#define AO_NEED_HSI	1 + +#define LEDS_AVAILABLE	(AO_LED_RED | AO_LED_GREEN) + +#define AO_POWER_MANAGEMENT	0 + +/* 48MHz clock based on USB */ +#define AO_HSI48	1 + +/* HCLK = 48MHz */ +#define AO_AHB_PRESCALER	1 +#define AO_RCC_CFGR_HPRE_DIV	STM_RCC_CFGR_HPRE_DIV_1 + +/* APB = 48MHz */ +#define AO_APB_PRESCALER	1 +#define AO_RCC_CFGR_PPRE_DIV	STM_RCC_CFGR_PPRE_DIV_1 + +#define HAS_USB				1 +#define AO_USB_DIRECTIO			0 +#define AO_PA11_PA12_RMP		1 +#define HAS_BEEP			0 + +#define IS_FLASH_LOADER	0 + +#endif /* _AO_PINS_H_ */ diff --git a/src/pnpservo-v1/ao_pnpservo.c b/src/pnpservo-v1/ao_pnpservo.c new file mode 100644 index 00000000..d4c2d495 --- /dev/null +++ b/src/pnpservo-v1/ao_pnpservo.c @@ -0,0 +1,36 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <ao.h> + +static const struct ao_cmds blink_cmds[] = { +//	{ lisp_cmd,	"l\0Run lisp interpreter" }, +	{ 0, 0 } +}; + + +void main(void) +{ +	ao_led_init(LEDS_AVAILABLE); +	ao_clock_init(); +	ao_task_init(); +	ao_timer_init(); +	ao_dma_init(); +	ao_usb_init(); +	ao_cmd_init(); +	ao_cmd_register(blink_cmds); +	ao_start_scheduler(); +} + + diff --git a/src/pnpservo-v1/flash-loader/.gitignore b/src/pnpservo-v1/flash-loader/.gitignore new file mode 100644 index 00000000..86ebb7f2 --- /dev/null +++ b/src/pnpservo-v1/flash-loader/.gitignore @@ -0,0 +1,2 @@ +ao_product.h +lambdakey* diff --git a/src/pnpservo-v1/flash-loader/Makefile b/src/pnpservo-v1/flash-loader/Makefile new file mode 100644 index 00000000..3283380c --- /dev/null +++ b/src/pnpservo-v1/flash-loader/Makefile @@ -0,0 +1,8 @@ +# +# AltOS flash loader build +# +# + +TOPDIR=../.. +HARDWARE=pnpservo-v1 +include $(TOPDIR)/stmf0/Makefile-flash.defs diff --git a/src/pnpservo-v1/flash-loader/ao_pins.h b/src/pnpservo-v1/flash-loader/ao_pins.h new file mode 100644 index 00000000..4b788f67 --- /dev/null +++ b/src/pnpservo-v1/flash-loader/ao_pins.h @@ -0,0 +1,37 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#include <ao_flash_stm_pins.h> + +/* Pin 5 on debug connector */ + +#define AO_BOOT_PIN			1 +#define AO_BOOT_APPLICATION_GPIO	stm_gpioa +#define AO_BOOT_APPLICATION_PIN		15 +#define AO_BOOT_APPLICATION_VALUE	1 +#define AO_BOOT_APPLICATION_MODE	AO_EXTI_MODE_PULL_UP + +/* USB */ +#define HAS_USB			1 +#define AO_USB_DIRECTIO		0 +#define AO_PA11_PA12_RMP	1 + +#endif /* _AO_PINS_H_ */ diff --git a/src/pnpservo-v1/lambda.ld b/src/pnpservo-v1/lambda.ld new file mode 100644 index 00000000..5de65eb5 --- /dev/null +++ b/src/pnpservo-v1/lambda.ld @@ -0,0 +1,117 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +MEMORY { +	rom (rx) :   ORIGIN = 0x08001000, LENGTH = 25K +	flash (r):   ORIGIN = 0x08007400, LENGTH = 3k +	ram (!w) :   ORIGIN = 0x20000000, LENGTH = 6k - 128 +	stack (!w) : ORIGIN = 0x20000000 + 6k - 128, LENGTH = 128 +} + +INCLUDE registers.ld + +EXTERN (stm_interrupt_vector) + +SECTIONS { +	/* +	 * Rom contents +	 */ + +	.interrupt ORIGIN(ram) : AT (ORIGIN(rom)) { +		__interrupt_start__ = .; +		__interrupt_rom__ = ORIGIN(rom); +		*(.interrupt)	/* Interrupt vectors */ +		__interrupt_end__ = .; +	} > ram + +	.text ORIGIN(rom) + 0x100 : { +		__text_start__ = .; + +		/* Ick. What I want is to specify the +		 * addresses of some global constants so +		 * that I can find them across versions +		 * of the application. I can't figure out +		 * how to make gnu ld do that, so instead +		 * we just load the two files that include +		 * these defines in the right order here and +		 * expect things to 'just work'. Don't change +		 * the contents of those files, ok? +		 */ +		ao_romconfig.o(.romconfig*) +		ao_product.o(.romconfig*) + +		*(.text*)	/* Executable code */ +		*(.ARM.exidx* .gnu.linkonce.armexidx.*) +		*(.rodata*)	/* Constants */ + +	} > rom +	__text_end__ = .; +	 + +	/* Boot data which must live at the start of ram so that +	 * the application and bootloader share the same addresses. +	 * This must be all uninitialized data +	 */ +	.boot (NOLOAD) : { +		__boot_start__ = .; +		*(.boot) +		. = ALIGN(4); +		__boot_end__ = .; +	} >ram + +	/* Functions placed in RAM (required for flashing) +	 * +	 * Align to 8 bytes as that's what the ARM likes text +	 * segment alignments to be, and if we don't, then +	 * we end up with a mismatch between the location in +	 * ROM and the desired location in RAM. I don't +	 * entirely understand this, but at least this appears +	 * to work... +	 */ + +	.textram BLOCK(8): { +		__data_start__ = .; +		__text_ram_start__ = .; +		*(.ramtext) +		__text_ram_end = .; +	} >ram AT>rom + +	/* Data -- relocated to RAM, but written to ROM +	 */ +	.data : { +		*(.data)	/* initialized data */ +		. = ALIGN(4); +		__data_end__ = .; +	} >ram AT>rom + +	.bss : { +		__bss_start__ = .; +		*(.bss) +		*(COMMON) +		. = ALIGN(4); +		__bss_end__ = .; +	} >ram + +	PROVIDE(end = .); + +	PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack)); + +	__flash__ = ORIGIN(flash); +} + +ENTRY(start); diff --git a/src/stm-vga/Makefile b/src/stm-vga/Makefile new file mode 100644 index 00000000..46a77272 --- /dev/null +++ b/src/stm-vga/Makefile @@ -0,0 +1,83 @@ +# +# AltOS build +# +# + +include ../stm/Makefile.defs + +INC = \ +	ao.h \ +	ao_arch.h \ +	ao_arch_funcs.h \ +	ao_boot.h \ +	ao_pins.h \ +	ao_product.h \ +	ao_vga.h \ +	ao_draw.h \ +	ao_draw_int.h \ +	ao_font.h \ +	ao_ps2.h + +# +# Common AltOS sources +# +ALTOS_SRC = \ +	ao_interrupt.c \ +	ao_boot_chain.c \ +	ao_product.c \ +	ao_romconfig.c \ +	ao_cmd.c \ +	ao_task.c \ +	ao_led.c \ +	ao_stdio.c \ +	ao_panic.c \ +	ao_timer.c \ +	ao_lcd_stm.c \ +	ao_lcd_font.c \ +	ao_vga.c \ +	ao_blt.c \ +	ao_copy.c \ +	ao_rect.c \ +	ao_text.c \ +	ao_line.c \ +	ao_mutex.c \ +	ao_dma_stm.c \ +	ao_adc_stm.c \ +	ao_data.c \ +	ao_i2c_stm.c \ +	ao_usb_stm.c \ +	ao_exti_stm.c \ +	ao_ps2.c \ +	ao_console.c + +PRODUCT=StmVga-v0.0 +IDPRODUCT=0x000a + +CFLAGS = $(STM_CFLAGS) -g -Os + +PROG=stm-vga-$(VERSION) +ELF=$(PROG).elf +IHX=$(PROG).ihx + +SRC=$(ALTOS_SRC) ao_demo.c +OBJ=$(SRC:.c=.o) + +all: $(ELF) $(IHX) + +$(ELF): Makefile $(OBJ) +	$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $@ $(OBJ) $(LIBS) + +ao_product.h: ao-make-product.5c ../Version +	$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +$(OBJ): $(INC) + +distclean:	clean + +clean: +	rm -f *.o *.elf *.ihx +	rm -f ao_product.h + +install: + +uninstall: diff --git a/src/stm-vga/ao_demo.c b/src/stm-vga/ao_demo.c new file mode 100644 index 00000000..1b443b1f --- /dev/null +++ b/src/stm-vga/ao_demo.c @@ -0,0 +1,233 @@ +/* + * Copyright © 2011 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" +#include <ao_exti.h> +#include <ao_event.h> +#include <ao_quadrature.h> +#include <ao_button.h> +#include <ao_boot.h> +#include <ao_vga.h> +#include <ao_ps2.h> +#include <ao_console.h> + +struct ao_task ball_task; +struct ao_task ps2_task; + +#define BALL_WIDTH	5 +#define BALL_HEIGHT	5 + +static int	ball_x; +static int	ball_y; +static int	ball_dx, ball_dy; + +uint8_t		ball_enable; + +void +ao_ball(void) +{ +	ball_dx = 1; +	ball_dy = 1; +	ball_x = 0; +	ball_y = 0; +	for (;;) { +		while (!ball_enable) +			ao_sleep(&ball_enable); +		for (;;) { +			ao_line(&ao_vga_bitmap, +				-100, -100, ball_x*2, ball_y*2, +				1, AO_XOR); +			ao_text(&ao_vga_bitmap, +				ball_x, ball_y - 10, +				"Hello, Bdale!", +				1, AO_XOR); +			ao_rect(&ao_vga_bitmap, +				ball_x, ball_y, +				BALL_WIDTH, +				BALL_HEIGHT, +				1, +				AO_XOR); +			ao_delay(AO_MS_TO_TICKS(10)); +			ao_rect(&ao_vga_bitmap, +				ball_x, ball_y, +				BALL_WIDTH, +				BALL_HEIGHT, +				1, +				AO_XOR); +			ao_text(&ao_vga_bitmap, +				ball_x, ball_y - 10, +				"Hello, Bdale!", +				1, AO_XOR); +			ao_line(&ao_vga_bitmap, +				-100, -100, ball_x*2, ball_y*2, +				1, AO_XOR); +			if (!ball_enable) +				break; +			ball_x += ball_dx; +			ball_y += ball_dy; +			if (ball_x + BALL_WIDTH > AO_VGA_WIDTH) { +				ball_x = AO_VGA_WIDTH - BALL_WIDTH; +				ball_dx = -ball_dx; +			} +			if (ball_x < 0) { +				ball_x = -ball_x; +				ball_dx = -ball_dx; +			} +			if (ball_y + BALL_HEIGHT > AO_VGA_HEIGHT) { +				ball_y = AO_VGA_HEIGHT - BALL_HEIGHT; +				ball_dy = -ball_dy; +			} +			if (ball_y < 0) { +				ball_y = -ball_y; +				ball_dy = -ball_dy; +			} +		} +	} +} + +void +ao_ps2(void) +{ +	uint8_t	leds = 0; +	for (;;) { +		uint8_t	b = ao_ps2_get(); +		printf ("%02x\n", b); +		flush(); +		if (b == 0x14) { +			leds ^= 4; +			ao_ps2_put(0xed); +			if (ao_ps2_get() == 0xfa) +				ao_ps2_put(leds); +		} +	} +} + +static void +ao_fb_init(void) +{ +	ao_rect(&ao_vga_bitmap, +		0, 0, AO_VGA_WIDTH, AO_VGA_HEIGHT, +		1, AO_COPY); + +	ao_rect(&ao_vga_bitmap, +		10, 10, 10, 10, +		0, AO_COPY); + +	ao_rect(&ao_vga_bitmap, +		AO_VGA_WIDTH - 20, 10, 10, 10, +		0, AO_COPY); + +	ao_rect(&ao_vga_bitmap, +		10, AO_VGA_HEIGHT - 20, 10, 10, +		0, AO_COPY); + +	ao_rect(&ao_vga_bitmap, +		AO_VGA_WIDTH - 20, AO_VGA_HEIGHT - 20, 10, 10, +		0, AO_COPY); + +	ao_text(&ao_vga_bitmap, +		20, 100, +		"Hello, Bdale!", +		0, AO_COPY); + +	ao_text(&ao_vga_bitmap, +		1, ao_font.ascent, +		"UL", +		0, AO_COPY); + +	ao_text(&ao_vga_bitmap, +		1, AO_VGA_HEIGHT - ao_font.descent, +		"BL", +		0, AO_COPY); +} + +static void +ao_video_toggle(void) +{ +	ao_cmd_decimal(); +	if (ao_cmd_lex_i) +		ao_fb_init(); +	ao_vga_enable(ao_cmd_lex_i); +} + +static void +ao_ball_toggle(void) +{ +	ao_cmd_decimal(); +	ball_enable = ao_cmd_lex_i; +	ao_wakeup(&ball_enable); +} + +static void +ao_ps2_read_keys(void) +{ +	char	c; + +	for (;;) { +		c = ao_ps2_getchar(); +		printf("%02x %c\n", c, ' ' <= c && c < 0x7f ? c : '.'); +		flush(); +		if (c == ' ') +			break; +	} +} + +static void +ao_console_send(void) +{ +	char	c; + +	while ((c = getchar()) != '~') { +		ao_console_putchar(c); +		flush(); +	} +} + +__code struct ao_cmds ao_demo_cmds[] = { +	{ ao_video_toggle, "V\0Toggle video" }, +	{ ao_ball_toggle, "B\0Toggle ball" }, +	{ ao_ps2_read_keys, "K\0Read keys from keyboard" }, +	{ ao_console_send, "C\0Send data to console, end with ~" }, +	{ 0, NULL } +}; + +int +main(void) +{ +	ao_clock_init(); + +	ao_task_init(); + +	ao_led_init(LEDS_AVAILABLE); +	ao_led_on(AO_LED_GREEN); +	ao_led_off(AO_LED_BLUE); +	ao_timer_init(); +	ao_dma_init(); +	ao_cmd_init(); +	ao_vga_init(); +	ao_usb_init(); +	ao_exti_init(); +	ao_ps2_init(); +	ao_console_init(); + +	ao_add_task(&ball_task, ao_ball, "ball"); +	ao_cmd_register(&ao_demo_cmds[0]); + +	ao_start_scheduler(); +	return 0; +} diff --git a/src/stm-vga/ao_lisp_os.h b/src/stm-vga/ao_lisp_os.h new file mode 100644 index 00000000..1993ac44 --- /dev/null +++ b/src/stm-vga/ao_lisp_os.h @@ -0,0 +1,62 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_LISP_OS_H_ +#define _AO_LISP_OS_H_ + +#include "ao.h" + +static inline int +ao_lisp_getc() { +	static uint8_t	at_eol; +	int c; + +	if (at_eol) { +		ao_cmd_readline(); +		at_eol = 0; +	} +	c = ao_cmd_lex(); +	if (c == '\n') +		at_eol = 1; +	return c; +} + +static inline void +ao_lisp_os_flush(void) +{ +	flush(); +} + +static inline void +ao_lisp_abort(void) +{ +	ao_panic(1); +} + +static inline void +ao_lisp_os_led(int led) +{ +	ao_led_set(led); +} + +static inline void +ao_lisp_os_delay(int delay) +{ +	ao_delay(AO_MS_TO_TICKS(delay)); +} + +#endif diff --git a/src/stm-vga/ao_lisp_os_save.c b/src/stm-vga/ao_lisp_os_save.c new file mode 100644 index 00000000..7c853990 --- /dev/null +++ b/src/stm-vga/ao_lisp_os_save.c @@ -0,0 +1,53 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <ao.h> +#include <ao_lisp.h> +#include <ao_flash.h> + +extern uint8_t	__flash__[]; + +/* saved variables to rebuild the heap + +   ao_lisp_atoms +   ao_lisp_frame_global + */ + +int +ao_lisp_os_save(void) +{ +	int i; + +	for (i = 0; i < AO_LISP_POOL_TOTAL; i += 256) { +		uint32_t	*dst = (uint32_t *) (void *) &__flash__[i]; +		uint32_t	*src = (uint32_t *) (void *) &ao_lisp_pool[i]; + +		ao_flash_page(dst, src); +	} +	return 1; +} + +int +ao_lisp_os_restore_save(struct ao_lisp_os_save *save, int offset) +{ +	memcpy(save, &__flash__[offset], sizeof (struct ao_lisp_os_save)); +	return 1; +} + +int +ao_lisp_os_restore(void) +{ +	memcpy(ao_lisp_pool, __flash__, AO_LISP_POOL_TOTAL); +	return 1; +} diff --git a/src/stm-vga/ao_pins.h b/src/stm-vga/ao_pins.h new file mode 100644 index 00000000..8503c4fd --- /dev/null +++ b/src/stm-vga/ao_pins.h @@ -0,0 +1,219 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +/* Bridge SB17 on the board and use the MCO from the other chip */ +#define AO_HSE			8000000 +#define AO_HSE_BYPASS		1 + +/* PLLVCO = 96MHz (so that USB will work) */ +#define AO_PLLMUL		12 +#define AO_RCC_CFGR_PLLMUL	(STM_RCC_CFGR_PLLMUL_12) + +/* SYSCLK = 24MHz */ +#define AO_PLLDIV		4 +#define AO_RCC_CFGR_PLLDIV	(STM_RCC_CFGR_PLLDIV_4) + +/* HCLK = 24MHZ (CPU clock) */ +#define AO_AHB_PRESCALER	1 +#define AO_RCC_CFGR_HPRE_DIV	STM_RCC_CFGR_HPRE_DIV_1 + +/* Run APB1 at HCLK/1 */ +#define AO_APB1_PRESCALER	1 +#define AO_RCC_CFGR_PPRE1_DIV	STM_RCC_CFGR_PPRE2_DIV_1 + +/* Run APB2 at HCLK/1 */ +#define AO_APB2_PRESCALER      	1 +#define AO_RCC_CFGR_PPRE2_DIV	STM_RCC_CFGR_PPRE2_DIV_1 + +/* Allow for non-maskable interrupts at priority 0 */ +#define AO_NONMASK_INTERRUPT	1 + +#define HAS_SERIAL_1		0 +#define USE_SERIAL_1_STDIN	0 +#define SERIAL_1_PB6_PB7	1 +#define SERIAL_1_PA9_PA10	0 + +#define HAS_SERIAL_2		0 +#define USE_SERIAL_2_STDIN	0 +#define SERIAL_2_PA2_PA3	0 +#define SERIAL_2_PD5_PD6	1 + +#define HAS_SERIAL_3		0 +#define USE_SERIAL_3_STDIN	1 +#define SERIAL_3_PB10_PB11	0 +#define SERIAL_3_PC10_PC11	0 +#define SERIAL_3_PD8_PD9	1 + +#define HAS_SPI_1		0 +#define SPI_1_PB3_PB4_PB5	1 +#define SPI_1_OSPEEDR		STM_OSPEEDR_10MHz + +#define HAS_SPI_2		0 + +#define HAS_USB			1 +#define HAS_BEEP		0 +#define PACKET_HAS_SLAVE	0 +#define HAS_TASK_QUEUE		1 + +#define CONSOLE_STDIN		1 + +#define AO_STACK_SIZE		1024 + +#define STM_DMA1_3_STOLEN	1 + +#define AO_BOOT_CHAIN		1 + +#define LOW_LEVEL_DEBUG		0 + +#define LED_PORT_ENABLE		STM_RCC_AHBENR_GPIOBEN +#define LED_PORT		(&stm_gpiob) +#define LED_PIN_GREEN		7 +#define LED_PIN_BLUE		6 +#define AO_LED_GREEN		(1 << LED_PIN_GREEN) +#define AO_LED_BLUE		(1 << LED_PIN_BLUE) +#define AO_LED_PANIC		AO_LED_BLUE + +#define LEDS_AVAILABLE		(AO_LED_BLUE | AO_LED_GREEN) + +#define AO_LCD_STM_SEG_ENABLED_0 (		\ +		(1 << 0) | /* PA1 */		\ +		(1 << 1) | /* PA2 */		\ +		(1 << 2) | /* PA3 */		\ +		(0 << 3) | /* PA6 */		\ +		(0 << 4) | /* PA7 */		\ +		(0 << 5) | /* PB0 */		\ +		(0 << 6) | /* PB1 */		\ +		(1 << 7) | /* PB3 */		\ +		(1 << 8) | /* PB4 */		\ +		(1 << 9) | /* PB5 */		\ +		(1 << 10) | /* PB10 */		\ +		(1 << 11) | /* PB11 */		\ +		(1 << 12) | /* PB12 */		\ +		(1 << 13) | /* PB13 */		\ +		(1 << 14) | /* PB14 */		\ +		(1 << 15) | /* PB15 */		\ +		(1 << 16) | /* PB8 */		\ +		(1 << 17) | /* PA15 */		\ +		(1 << 18) | /* PC0 */		\ +		(1 << 19) | /* PC1 */		\ +		(1 << 20) | /* PC2 */		\ +		(1 << 21) | /* PC3 */		\ +		(0 << 22) | /* PC4 */		\ +		(0 << 23) | /* PC5 */		\ +		(1 << 24) | /* PC6 */		\ +		(1 << 25) | /* PC7 */		\ +		(1 << 26) | /* PC8 */		\ +		(1 << 27) | /* PC9 */		\ +		(1 << 28) | /* PC10 or PD8 */	\ +		(1 << 29) | /* PC11 or PD9 */	\ +		(0 << 30) | /* PC12 or PD10 */	\ +		(0 << 31))  /* PD2 or PD11 */ + +#define AO_LCD_STM_SEG_ENABLED_1 (		\ +		(0 << 0) | /* PD12 */		\ +		(0 << 1) | /* PD13 */		\ +		(0 << 2) | /* PD14 */		\ +		(0 << 3) | /* PD15 */		\ +		(0 << 4) | /* PE0 */		\ +		(0 << 5) | /* PE1 */		\ +		(0 << 6) | /* PE2 */		\ +		(0 << 7))  /* PE3 */ + +#define AO_LCD_STM_COM_ENABLED (		\ +		(1 << 0) | /* PA8 */		\ +		(1 << 1) | /* PA9 */		\ +		(1 << 2) | /* PA10 */		\ +		(1 << 3) | /* PB9 */		\ +		(0 << 4) | /* PC10 */		\ +		(0 << 5) | /* PC11 */		\ +		(0 << 6)) /* PC12 */ + +#define AO_LCD_28_ON_C	1 + +#define AO_LCD_DUTY	STM_LCD_CR_DUTY_STATIC + +#define HAS_ADC			1 + +#define AO_ADC_RING		32 + +struct ao_adc { +	uint16_t		tick; +	int16_t			idd; +	int16_t			temp; +	int16_t			vref; +}; + +#define AO_ADC_IDD		4 +#define AO_ADC_PIN0_PORT	(&stm_gpioa) +#define AO_ADC_PIN0_PIN		4 + +#define AO_ADC_RCC_AHBENR	((1 << STM_RCC_AHBENR_GPIOAEN)) +#define AO_ADC_TEMP		16 +#define AO_ADC_VREF		17 + +#define HAS_ADC_TEMP		1 + +#define AO_DATA_RING		32 +#define AO_NUM_ADC		3 + +#define AO_ADC_SQ1		AO_ADC_IDD +#define AO_ADC_SQ2		AO_ADC_TEMP +#define AO_ADC_SQ3		AO_ADC_VREF +	 +#define HAS_I2C_1		1 +#define I2C_1_PB6_PB7		0 +#define I2C_1_PB8_PB9		1 + +#define HAS_I2C_2		0 +#define I2C_2_PB10_PB11		0 + +#define AO_EVENT		1 + +#define AO_QUADRATURE_COUNT	2 +#define AO_QUADRATURE_MODE	AO_EXTI_MODE_PULL_UP + +#define AO_QUADRATURE_0_PORT	&stm_gpioc +#define AO_QUADRATURE_0_A	1 +#define AO_QUADRATURE_0_B	0 + +#define AO_QUADRATURE_1_PORT	&stm_gpioc +#define AO_QUADRATURE_1_A	3 +#define AO_QUADRATURE_1_B	2 + +#define AO_BUTTON_COUNT		2 +#define AO_BUTTON_MODE		AO_EXTI_MODE_PULL_UP + +#define AO_BUTTON_0_PORT	&stm_gpioc +#define AO_BUTTON_0		6 + +#define AO_BUTTON_1_PORT	&stm_gpioc +#define AO_BUTTON_1		7 + +#define AO_TICK_TYPE		uint32_t +#define AO_TICK_SIGNED		int32_t + +#define AO_PS2_CLOCK_PORT	(&stm_gpioc) +#define AO_PS2_CLOCK_BIT	0 + +#define AO_PS2_DATA_PORT	(&stm_gpioc) +#define AO_PS2_DATA_BIT		1 + +#endif /* _AO_PINS_H_ */ diff --git a/src/stm/Makefile.defs b/src/stm/Makefile.defs index 0ba86f5a..66ed4be8 100644 --- a/src/stm/Makefile.defs +++ b/src/stm/Makefile.defs @@ -1,4 +1,4 @@ -vpath % ../stm:../product:../drivers:../kernel:../util:../kalman:../aes:../math:.. +vpath % ../stm:../product:../drivers:../kernel:../util:../kalman:../aes:../math:../draw:../lisp:..  vpath make-altitude ../util  vpath make-kalman ../util  vpath kalman.5c ../kalman @@ -26,7 +26,7 @@ LIBS=$(PDCLIB_LIBS_M3) -lgcc  WARN_FLAGS=-Wall -Wextra -Werror -AO_CFLAGS=-I. -I../stm -I../kernel -I../drivers -I../math -I.. $(PDCLIB_INCLUDES) +AO_CFLAGS=-I. -I../stm -I../kernel -I../drivers -I../math -I../draw -I../lisp -I.. $(PDCLIB_INCLUDES)  STM_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m3 -mthumb -Wcast-align \  	-ffreestanding -nostdlib $(AO_CFLAGS) $(WARN_FLAGS) diff --git a/src/stm/altos-512.ld b/src/stm/altos-512.ld new file mode 100644 index 00000000..78c41685 --- /dev/null +++ b/src/stm/altos-512.ld @@ -0,0 +1,98 @@ +/* + * Copyright © 2017 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +MEMORY { +	rom (rx) : ORIGIN = 0x08001000, LENGTH = 508K +	ram (!w) : ORIGIN = 0x20000000, LENGTH = 81408 +	stack (!w) : ORIGIN = 0x20013e00, LENGTH = 512 +} + +INCLUDE registers.ld + +EXTERN (stm_interrupt_vector) + +SECTIONS { +	/* +	 * Rom contents +	 */ + +	.text ORIGIN(rom) : { +		__text_start__ = .; +		*(.interrupt)	/* Interrupt vectors */ + +		. = ORIGIN(rom) + 0x100; + + +		/* Ick. What I want is to specify the +		 * addresses of some global constants so +		 * that I can find them across versions +		 * of the application. I can't figure out +		 * how to make gnu ld do that, so instead +		 * we just load the two files that include +		 * these defines in the right order here and +		 * expect things to 'just work'. Don't change +		 * the contents of those files, ok? +		 */ +		ao_romconfig.o(.romconfig*) +		ao_product.o(.romconfig*) +		*(.text*)	/* Executable code */ +		*(.rodata*)	/* Constants */ + +	} > rom + +	.ARM.exidx : { +		*(.ARM.exidx* .gnu.linkonce.armexidx.*) +	} > rom +	__text_end__ = .; + +	/* Boot data which must live at the start of ram so that +	 * the application and bootloader share the same addresses. +	 * This must be all uninitialized data +	 */ +	.boot (NOLOAD) : { +		__boot_start__ = .; +		*(.boot) +		. = ALIGN(4); +		__boot_end__ = .; +	} >ram + +	/* Data -- relocated to RAM, but written to ROM +	 */ +	.data : { +		__data_start__ = .; +		*(.data)	/* initialized data */ +		. = ALIGN(4); +		__data_end__ = .; +	} >ram AT>rom + +	.bss : { +		__bss_start__ = .; +		*(.bss) +		*(COMMON) +		. = ALIGN(4); +		__bss_end__ = .; +	} >ram + +	PROVIDE(end = .); + +	PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack)); +} + +ENTRY(start); + + diff --git a/src/stm/ao_arch.h b/src/stm/ao_arch.h index 0cc29376..5f033b66 100644 --- a/src/stm/ao_arch.h +++ b/src/stm/ao_arch.h @@ -85,10 +85,6 @@ extern const uint32_t ao_radio_cal;  #define ao_arch_task_members\  	uint32_t *sp;			/* saved stack pointer */ -#define ao_arch_block_interrupts()	asm("cpsid i") -#define ao_arch_release_interrupts()	asm("cpsie i") - -  /*   * For now, we're running at a weird frequency   */ @@ -122,10 +118,21 @@ extern const uint32_t ao_radio_cal;  #define AO_TIM91011_CLK		(2 * AO_PCLK2)  #endif -#define AO_STM_NVIC_HIGH_PRIORITY	4 -#define AO_STM_NVIC_CLOCK_PRIORITY	6 -#define AO_STM_NVIC_MED_PRIORITY	8 -#define AO_STM_NVIC_LOW_PRIORITY	10 +/* The stm32l implements only 4 bits of the priority fields */ + +#if AO_NONMASK_INTERRUPT +#define AO_STM_NVIC_NONMASK_PRIORITY	0x00 + +/* Set the basepri register to this value to mask all + * non-maskable priorities + */ +#define AO_STM_NVIC_BASEPRI_MASK	0x10 +#endif + +#define AO_STM_NVIC_HIGH_PRIORITY	0x40 +#define AO_STM_NVIC_MED_PRIORITY	0x80 +#define AO_STM_NVIC_LOW_PRIORITY	0xC0 +#define AO_STM_NVIC_CLOCK_PRIORITY	0xf0  void ao_lcd_stm_init(void); diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index a9d0fa34..522059bc 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -202,8 +202,11 @@ ao_spi_try_get_mask(struct stm_gpio *reg, uint16_t mask, uint8_t bus, uint32_t s  #define ao_gpio_set_bits(port, bits) stm_gpio_set_bits(port, bits) +#define ao_gpio_set_mask(port, bits, mask) stm_gpio_set_mask(port, bits, mask) +  #define ao_gpio_clr_bits(port, bits) stm_gpio_clr_bits(port, bits); +#define ao_gpio_get_all(port) stm_gpio_get_all(port)  #define ao_enable_output(port,bit,pin,v) do {			\  		ao_enable_port(port);				\ @@ -211,6 +214,18 @@ ao_spi_try_get_mask(struct stm_gpio *reg, uint16_t mask, uint8_t bus, uint32_t s  		stm_moder_set(port, bit, STM_MODER_OUTPUT);\  	} while (0) +#define ao_enable_output_mask(port,bits,mask) do {		\ +		ao_enable_port(port);				\ +		ao_gpio_set_mask(port, bits, mask);		\ +		ao_set_output_mask(port, mask);			\ +	} while (0) + +#define AO_OUTPUT_PUSH_PULL	STM_OTYPER_PUSH_PULL +#define AO_OUTPUT_OPEN_DRAIN	STM_OTYPER_OPEN_DRAIN + +#define ao_gpio_set_output_mode(port,bit,pin,mode) \ +	stm_otyper_set(port, pin, mode) +  #define ao_gpio_set_mode(port,bit,mode) do {				\  		if (mode == AO_EXTI_MODE_PULL_UP)			\  			stm_pupdr_set(port, bit, STM_PUPDR_PULL_UP);	\ @@ -219,36 +234,73 @@ ao_spi_try_get_mask(struct stm_gpio *reg, uint16_t mask, uint8_t bus, uint32_t s  		else							\  			stm_pupdr_set(port, bit, STM_PUPDR_NONE);	\  	} while (0) -	 + +#define ao_gpio_set_mode_mask(port,mask,mode) do {			\ +		if (mode == AO_EXTI_MODE_PULL_UP)			\ +			stm_pupdr_set_mask(port, mask, STM_PUPDR_PULL_UP); \ +		else if (mode == AO_EXTI_MODE_PULL_DOWN)		\ +			stm_pupdr_set_mask(port, mask, STM_PUPDR_PULL_DOWN); \ +		else							\ +			stm_pupdr_set_mask(port, mask, STM_PUPDR_NONE);	\ +	} while (0) + +#define ao_set_input(port, bit) do {				\ +		stm_moder_set(port, bit, STM_MODER_INPUT);	\ +	} while (0) + +#define ao_set_output(port, bit, pin, v) do {			\ +		ao_gpio_set(port, bit, pin, v);			\ +		stm_moder_set(port, bit, STM_MODER_OUTPUT);	\ +	} while (0) + +#define ao_set_output_mask(port, mask) do {			\ +		stm_moder_set_mask(port, mask, STM_MODER_OUTPUT);	\ +	} while (0) + +#define ao_set_input_mask(port, mask) do {				\ +		stm_moder_set_mask(port, mask, STM_MODER_INPUT);	\ +	} while (0) +  #define ao_enable_input(port,bit,mode) do {				\  		ao_enable_port(port);					\ -		stm_moder_set(port, bit, STM_MODER_INPUT);		\ +		ao_set_input(port, bit);				\  		ao_gpio_set_mode(port, bit, mode);			\  	} while (0) -#define ao_enable_cs(port,bit) do {				\ +#define ao_enable_input_mask(port,mask,mode) do {	\ +		ao_enable_port(port);			\ +		ao_gpio_set_mode_mask(port, mask, mode);	\ +		ao_set_input_mask(port, mask);		\ +	} while (0) + +#define _ao_enable_cs(port, bit) do {				\  		stm_gpio_set((port), bit, 1);			\  		stm_moder_set((port), bit, STM_MODER_OUTPUT);	\  	} while (0) +#define ao_enable_cs(port,bit) do {				\ +		ao_enable_port(port);				\ +		_ao_enable_cs(port, bit);			\ +	} while (0) +  #define ao_spi_init_cs(port, mask) do {				\  		ao_enable_port(port);				\ -		if ((mask) & 0x0001) ao_enable_cs(port, 0);	\ -		if ((mask) & 0x0002) ao_enable_cs(port, 1);	\ -		if ((mask) & 0x0004) ao_enable_cs(port, 2);	\ -		if ((mask) & 0x0008) ao_enable_cs(port, 3);	\ -		if ((mask) & 0x0010) ao_enable_cs(port, 4);	\ -		if ((mask) & 0x0020) ao_enable_cs(port, 5);	\ -		if ((mask) & 0x0040) ao_enable_cs(port, 6);	\ -		if ((mask) & 0x0080) ao_enable_cs(port, 7);	\ -		if ((mask) & 0x0100) ao_enable_cs(port, 8);	\ -		if ((mask) & 0x0200) ao_enable_cs(port, 9);	\ -		if ((mask) & 0x0400) ao_enable_cs(port, 10);\ -		if ((mask) & 0x0800) ao_enable_cs(port, 11);\ -		if ((mask) & 0x1000) ao_enable_cs(port, 12);\ -		if ((mask) & 0x2000) ao_enable_cs(port, 13);\ -		if ((mask) & 0x4000) ao_enable_cs(port, 14);\ -		if ((mask) & 0x8000) ao_enable_cs(port, 15);\ +		if ((mask) & 0x0001) _ao_enable_cs(port, 0);	\ +		if ((mask) & 0x0002) _ao_enable_cs(port, 1);	\ +		if ((mask) & 0x0004) _ao_enable_cs(port, 2);	\ +		if ((mask) & 0x0008) _ao_enable_cs(port, 3);	\ +		if ((mask) & 0x0010) _ao_enable_cs(port, 4);	\ +		if ((mask) & 0x0020) _ao_enable_cs(port, 5);	\ +		if ((mask) & 0x0040) _ao_enable_cs(port, 6);	\ +		if ((mask) & 0x0080) _ao_enable_cs(port, 7);	\ +		if ((mask) & 0x0100) _ao_enable_cs(port, 8);	\ +		if ((mask) & 0x0200) _ao_enable_cs(port, 9);	\ +		if ((mask) & 0x0400) _ao_enable_cs(port, 10);\ +		if ((mask) & 0x0800) _ao_enable_cs(port, 11);\ +		if ((mask) & 0x1000) _ao_enable_cs(port, 12);\ +		if ((mask) & 0x2000) _ao_enable_cs(port, 13);\ +		if ((mask) & 0x4000) _ao_enable_cs(port, 14);\ +		if ((mask) & 0x8000) _ao_enable_cs(port, 15);\  	} while (0)  /* ao_dma_stm.c @@ -345,17 +397,43 @@ extern struct ao_stm_usart	ao_stm_usart3;  typedef uint32_t	ao_arch_irq_t; +static inline void +ao_arch_block_interrupts(void) { +#ifdef AO_NONMASK_INTERRUPTS +	asm("msr basepri,%0" : : "r" (AO_STM_NVIC_BASEPRI_MASK)); +#else +	asm("cpsid i"); +#endif +} + +static inline void +ao_arch_release_interrupts(void) { +#ifdef AO_NONMASK_INTERRUPTS +	asm("msr basepri,%0" : : "r" (0x0)); +#else +	asm("cpsie i"); +#endif +} +  static inline uint32_t  ao_arch_irqsave(void) { -	uint32_t	primask; -	asm("mrs %0,primask" : "=&r" (primask)); +	uint32_t	val; +#ifdef AO_NONMASK_INTERRUPTS +	asm("mrs %0,basepri" : "=r" (val)); +#else +	asm("mrs %0,primask" : "=r" (val)); +#endif  	ao_arch_block_interrupts(); -	return primask; +	return val;  }  static inline void -ao_arch_irqrestore(uint32_t primask) { -	asm("msr primask,%0" : : "r" (primask)); +ao_arch_irqrestore(uint32_t basepri) { +#ifdef AO_NONMASK_INTERRUPTS +	asm("msr basepri,%0" : : "r" (basepri)); +#else +	asm("msr primask,%0" : : "r" (basepri)); +#endif  }  static inline void @@ -365,10 +443,17 @@ ao_arch_memory_barrier() {  static inline void  ao_arch_irq_check(void) { +#ifdef AO_NONMASK_INTERRUPTS +	uint32_t	basepri; +	asm("mrs %0,basepri" : "=r" (basepri)); +	if (basepri == 0) +		ao_panic(AO_PANIC_IRQ); +#else  	uint32_t	primask; -	asm("mrs %0,primask" : "=&r" (primask)); +	asm("mrs %0,primask" : "=r" (primask));  	if ((primask & 1) == 0)  		ao_panic(AO_PANIC_IRQ); +#endif  }  #if HAS_TASK @@ -390,7 +475,7 @@ ao_arch_init_stack(struct ao_task *task, void *start)  	/* APSR */  	ARM_PUSH32(sp, 0); -	/* PRIMASK with interrupts enabled */ +	/* BASEPRI with interrupts enabled */  	ARM_PUSH32(sp, 0);  	task->sp = sp; @@ -404,8 +489,13 @@ static inline void ao_arch_save_regs(void) {  	asm("mrs r0,apsr");  	asm("push {r0}"); +#ifdef AO_NONMASK_INTERRUPTS +	/* Save BASEPRI */ +	asm("mrs r0,basepri"); +#else  	/* Save PRIMASK */  	asm("mrs r0,primask"); +#endif  	asm("push {r0}");  } @@ -419,9 +509,15 @@ static inline void ao_arch_restore_stack(void) {  	/* Switch stacks */  	asm("mov sp, %0" : : "r" (ao_cur_task->sp) ); +#ifdef AO_NONMASK_INTERRUPTS +	/* Restore BASEPRI */ +	asm("pop {r0}"); +	asm("msr basepri,r0"); +#else  	/* Restore PRIMASK */  	asm("pop {r0}");  	asm("msr primask,r0"); +#endif  	/* Restore APSR */  	asm("pop {r0}"); @@ -463,7 +559,7 @@ static inline void ao_arch_start_scheduler(void) {  	asm("mrs %0,msp" : "=&r" (sp));  	asm("msr psp,%0" : : "r" (sp)); -	asm("mrs %0,control" : "=&r" (control)); +	asm("mrs %0,control" : "=r" (control));  	control |= (1 << 1);  	asm("msr control,%0" : : "r" (control));  	asm("isb"); @@ -474,12 +570,24 @@ static inline void ao_arch_start_scheduler(void) {  #endif -#define ao_arch_wait_interrupt() do {				\ -		asm("\twfi\n");					\ -		ao_arch_release_interrupts();			\ -		asm(".global ao_idle_loc\nao_idle_loc:");	\ -		ao_arch_block_interrupts();			\ -	} while (0) +static inline void +ao_arch_wait_interrupt(void) { +#ifdef AO_NONMASK_INTERRUPTS +	asm( +	    "dsb\n"			/* Serialize data */ +	    "isb\n"			/* Serialize instructions */ +	    "cpsid i\n"			/* Block all interrupts */ +	    "msr basepri,%0\n"		/* Allow all interrupts through basepri */ +	    "wfi\n"			/* Wait for an interrupt */ +	    "cpsie i\n"			/* Allow all interrupts */ +	    "msr basepri,%1\n"		/* Block interrupts through basepri */ +	    : : "r" (0), "r" (AO_STM_NVIC_BASEPRI_MASK)); +#else +	asm("\twfi\n"); +	ao_arch_release_interrupts(); +	ao_arch_block_interrupts(); +#endif +}  #define ao_arch_critical(b) do {			\  		uint32_t __mask = ao_arch_irqsave();	\ diff --git a/src/stm/ao_dma_stm.c b/src/stm/ao_dma_stm.c index 6d779660..962b3acc 100644 --- a/src/stm/ao_dma_stm.c +++ b/src/stm/ao_dma_stm.c @@ -29,7 +29,6 @@ uint8_t ao_dma_done[NUM_DMA];  static struct ao_dma_config ao_dma_config[NUM_DMA];  static uint8_t ao_dma_allocated[NUM_DMA];  static uint8_t ao_dma_mutex[NUM_DMA]; -static uint8_t ao_dma_active;  static void  ao_dma_isr(uint8_t index) { @@ -49,12 +48,24 @@ ao_dma_isr(uint8_t index) {  void stm_dma1_channel1_isr(void) { ao_dma_isr(STM_DMA_INDEX(1)); }  void stm_dma1_channel2_isr(void) { ao_dma_isr(STM_DMA_INDEX(2)); } +#ifdef STM_DMA1_3_STOLEN +#define LEAVE_DMA_ON +#else  void stm_dma1_channel3_isr(void) { ao_dma_isr(STM_DMA_INDEX(3)); } +#endif  void stm_dma1_channel4_isr(void) { ao_dma_isr(STM_DMA_INDEX(4)); } +#ifdef STM_DMA1_5_STOLEN +#define LEAVE_DMA_ON +#else  void stm_dma1_channel5_isr(void) { ao_dma_isr(STM_DMA_INDEX(5)); } +#endif  void stm_dma1_channel6_isr(void) { ao_dma_isr(STM_DMA_INDEX(6)); }  void stm_dma1_channel7_isr(void) { ao_dma_isr(STM_DMA_INDEX(7)); } +#ifndef LEAVE_DMA_ON +static uint8_t ao_dma_active; +#endif +  void  ao_dma_set_transfer(uint8_t 		index,  		    volatile void	*peripheral, @@ -68,10 +79,12 @@ ao_dma_set_transfer(uint8_t 		index,  		ao_dma_mutex[index] = 0xff;  	} else  		ao_mutex_get(&ao_dma_mutex[index]); +#ifndef LEAVE_DMA_ON  	ao_arch_critical(  		if (ao_dma_active++ == 0)  			stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_DMA1EN);  		); +#endif  	stm_dma.channel[index].ccr = ccr | (1 << STM_DMA_CCR_TCIE);  	stm_dma.channel[index].cndtr = count;  	stm_dma.channel[index].cpar = peripheral; @@ -96,10 +109,12 @@ void  ao_dma_done_transfer(uint8_t index)  {  	stm_dma.channel[index].ccr &= ~(1 << STM_DMA_CCR_EN); +#ifndef LEAVE_DMA_ON  	ao_arch_critical(  		if (--ao_dma_active == 0)  			stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_DMA1EN);  		); +#endif  	if (ao_dma_allocated[index])  		ao_dma_mutex[index] = 0;  	else @@ -120,10 +135,12 @@ ao_dma_dump_cmd(void)  {  	int i; +#ifndef LEAVE_DMA_ON  	ao_arch_critical(  		if (ao_dma_active++ == 0)  			stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_DMA1EN);  		); +#endif  	printf ("isr %08x ifcr%08x\n", stm_dma.isr, stm_dma.ifcr);  	for (i = 0; i < NUM_DMA; i++)  		printf("%d: done %d allocated %d mutex %2d ccr %04x cndtr %04x cpar %08x cmar %08x isr %08x\n", @@ -136,10 +153,12 @@ ao_dma_dump_cmd(void)  		       stm_dma.channel[i].cpar,  		       stm_dma.channel[i].cmar,  		       ao_dma_config[i].isr); +#ifndef LEAVE_DMA_ON  	ao_arch_critical(  		if (--ao_dma_active == 0)  			stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_DMA1EN);  		); +#endif  }  static const struct ao_cmds ao_dma_cmds[] = { @@ -153,9 +172,27 @@ ao_dma_init(void)  {  	int	index; +#ifdef LEAVE_DMA_ON +	stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_DMA1EN); +#endif  	for (index = 0; index < STM_NUM_DMA; index++) { +#if STM_DMA1_5_STOLEN +		if (index == STM_DMA_INDEX(5)) { +			ao_dma_allocated[index] = 1; +			ao_dma_mutex[index] = 0xff; +			continue; +		} +#endif +#if STM_DMA1_3_STOLEN +		if (index == STM_DMA_INDEX(3)) { +			ao_dma_allocated[index] = 1; +			ao_dma_mutex[index] = 0xff; +			continue; +		} +#endif  		stm_nvic_set_enable(STM_ISR_DMA1_CHANNEL1_POS + index); -		stm_nvic_set_priority(STM_ISR_DMA1_CHANNEL1_POS + index, 4); +		stm_nvic_set_priority(STM_ISR_DMA1_CHANNEL1_POS + index, +				      AO_STM_NVIC_MED_PRIORITY);  		ao_dma_allocated[index] = 0;  		ao_dma_mutex[index] = 0;  	} diff --git a/src/stm/ao_exti_stm.c b/src/stm/ao_exti_stm.c index 3e0b3e5c..2491b609 100644 --- a/src/stm/ao_exti_stm.c +++ b/src/stm/ao_exti_stm.c @@ -123,7 +123,7 @@ ao_exti_set_mode(struct stm_gpio *gpio, uint8_t pin, uint8_t mode) {  	(void) gpio;  	uint32_t	mask = 1 << pin; -	 +  	if (mode & AO_EXTI_MODE_RISING)  		stm_exti.rtsr |= mask;  	else diff --git a/src/stm/ao_flash_stm.c b/src/stm/ao_flash_stm.c index c1648421..38618bbe 100644 --- a/src/stm/ao_flash_stm.c +++ b/src/stm/ao_flash_stm.c @@ -74,11 +74,10 @@ static void __attribute__ ((section(".ramtext"),noinline))  _ao_flash_erase_page(uint32_t *page)  {  	stm_flash.pecr |= (1 << STM_FLASH_PECR_ERASE) | (1 << STM_FLASH_PECR_PROG); -	 +  	*page = 0x00000000; -	while (stm_flash.sr & (1 << STM_FLASH_SR_BSY)) -		; +	ao_flash_wait_bsy();  }  void @@ -101,9 +100,8 @@ _ao_flash_half_page(uint32_t *dst, uint32_t *src)  	stm_flash.pecr |= (1 << STM_FLASH_PECR_FPRG);  	stm_flash.pecr |= (1 << STM_FLASH_PECR_PROG); -	 -	while (stm_flash.sr & (1 << STM_FLASH_SR_BSY)) -		; + +	ao_flash_wait_bsy();  	for (i = 0; i < 32; i++) {  		*dst++ = *src++; diff --git a/src/stm/ao_i2c_stm.c b/src/stm/ao_i2c_stm.c index 29a8f173..59cad495 100644 --- a/src/stm/ao_i2c_stm.c +++ b/src/stm/ao_i2c_stm.c @@ -75,6 +75,9 @@ uint8_t 	ao_i2c_mutex[STM_NUM_I2C];  #if AO_PCLK1 == 16000000  # define AO_STM_I2C_CR2_FREQ	STM_I2C_CR2_FREQ_16_MHZ  #endif +#if AO_PCLK1 == 24000000 +# define AO_STM_I2C_CR2_FREQ	STM_I2C_CR2_FREQ_24_MHZ +#endif  #if AO_PCLK1 == 32000000  # define AO_STM_I2C_CR2_FREQ	STM_I2C_CR2_FREQ_32_MHZ  #endif diff --git a/src/stm/ao_serial_stm.c b/src/stm/ao_serial_stm.c index db0be992..c625471e 100644 --- a/src/stm/ao_serial_stm.c +++ b/src/stm/ao_serial_stm.c @@ -444,7 +444,7 @@ ao_serial_init(void)  	ao_usart_init(&ao_stm_usart1);  	stm_nvic_set_enable(STM_ISR_USART1_POS); -	stm_nvic_set_priority(STM_ISR_USART1_POS, 4); +	stm_nvic_set_priority(STM_ISR_USART1_POS, AO_STM_NVIC_MED_PRIORITY);  #if USE_SERIAL_1_STDIN && !DELAY_SERIAL_1_STDIN  	ao_add_stdio(_ao_serial1_pollchar,  		     ao_serial1_putchar, @@ -500,7 +500,7 @@ ao_serial_init(void)  #endif  	stm_nvic_set_enable(STM_ISR_USART2_POS); -	stm_nvic_set_priority(STM_ISR_USART2_POS, 4); +	stm_nvic_set_priority(STM_ISR_USART2_POS, AO_STM_NVIC_MED_PRIORITY);  #if USE_SERIAL_2_STDIN && !DELAY_SERIAL_2_STDIN  	ao_add_stdio(_ao_serial2_pollchar,  		     ao_serial2_putchar, @@ -544,7 +544,7 @@ ao_serial_init(void)  	ao_usart_init(&ao_stm_usart3);  	stm_nvic_set_enable(STM_ISR_USART3_POS); -	stm_nvic_set_priority(STM_ISR_USART3_POS, 4); +	stm_nvic_set_priority(STM_ISR_USART3_POS, AO_STM_NVIC_MED_PRIORITY);  #if USE_SERIAL_3_STDIN && !DELAY_SERIAL_3_STDIN  	ao_add_stdio(_ao_serial3_pollchar,  		     ao_serial3_putchar, diff --git a/src/stm/ao_timer.c b/src/stm/ao_timer.c index f86a5116..1576a6c9 100644 --- a/src/stm/ao_timer.c +++ b/src/stm/ao_timer.c @@ -90,6 +90,7 @@ ao_timer_init(void)  	stm_systick.csr = ((1 << STM_SYSTICK_CSR_ENABLE) |  			   (1 << STM_SYSTICK_CSR_TICKINT) |  			   (STM_SYSTICK_CSR_CLKSOURCE_HCLK_8 << STM_SYSTICK_CSR_CLKSOURCE)); +	stm_nvic.shpr15_12 |= AO_STM_NVIC_CLOCK_PRIORITY << 24;  }  #endif diff --git a/src/stm/ao_usb_stm.c b/src/stm/ao_usb_stm.c index 9d72844e..33e0617c 100644 --- a/src/stm/ao_usb_stm.c +++ b/src/stm/ao_usb_stm.c @@ -1015,7 +1015,7 @@ ao_usb_enable(void)  	ao_arch_block_interrupts();  	/* Route interrupts */ -	stm_nvic_set_priority(STM_ISR_USB_LP_POS, 3); +	stm_nvic_set_priority(STM_ISR_USB_LP_POS, AO_STM_NVIC_LOW_PRIORITY);  	stm_nvic_set_enable(STM_ISR_USB_LP_POS);  	ao_usb_configuration = 0; @@ -1109,7 +1109,7 @@ struct ao_usb_dbg {  	int		line;  	char		*msg;  	uint32_t	value; -	uint32_t	primask; +	uint32_t	prival;  #if TX_DBG  	uint16_t	in_count;  	uint32_t	in_epr; @@ -1125,19 +1125,23 @@ struct ao_usb_dbg {  #endif  }; -#define NUM_USB_DBG	128 +#define NUM_USB_DBG	16 -static struct ao_usb_dbg dbg[128]; +static struct ao_usb_dbg dbg[NUM_USB_DBG];  static int dbg_i;  static void _dbg(int line, char *msg, uint32_t value)  { -	uint32_t	primask; +	uint32_t	prival;  	dbg[dbg_i].line = line;  	dbg[dbg_i].msg = msg;  	dbg[dbg_i].value = value; -	asm("mrs %0,primask" : "=&r" (primask)); -	dbg[dbg_i].primask = primask; +#if AO_NONMASK_INTERRUPT +	asm("mrs %0,basepri" : "=&r" (prival)); +#else +	asm("mrs %0,primask" : "=&r" (prival)); +#endif +	dbg[dbg_i].prival = prival;  #if TX_DBG  	dbg[dbg_i].in_count = in_count;  	dbg[dbg_i].in_epr = stm_usb.epr[AO_USB_IN_EPR]; diff --git a/src/stm/stm32l.h b/src/stm/stm32l.h index be1e1d65..201f4f36 100644 --- a/src/stm/stm32l.h +++ b/src/stm/stm32l.h @@ -52,7 +52,32 @@ stm_moder_set(struct stm_gpio *gpio, int pin, vuint32_t value) {  			~(STM_MODER_MASK << STM_MODER_SHIFT(pin))) |  		       value << STM_MODER_SHIFT(pin));  } -	 + +static inline uint32_t +stm_spread_mask(uint16_t mask) { +	uint32_t m = mask; + +	/* 0000000000000000mmmmmmmmmmmmmmmm */ +	m = (m & 0xff) | ((m & 0xff00) << 8); +	/* 00000000mmmmmmmm00000000mmmmmmmm */ +	m = (m & 0x000f000f) | ((m & 0x00f000f0) << 4); +	/* 0000mmmm0000mmmm0000mmmm0000mmmm */ +	m = (m & 0x03030303) | ((m & 0x0c0c0c0c) << 2); +	/* 00mm00mm00mm00mm00mm00mm00mm00mm */ +	m = (m & 0x11111111) | ((m & 0x22222222) << 2); +	/* 0m0m0m0m0m0m0m0m0m0m0m0m0m0m0m0m */ +	return m; +} + +static inline void +stm_moder_set_mask(struct stm_gpio *gpio, uint16_t mask, uint32_t value) { +	uint32_t	bits32 = stm_spread_mask(mask); +	uint32_t	mask32 = 3 * bits32; +	uint32_t	value32 = (value & 3) * bits32; + +	gpio->moder = ((gpio->moder & ~mask32) | value32); +} +  static inline uint32_t  stm_moder_get(struct stm_gpio *gpio, int pin) {  	return (gpio->moder >> STM_MODER_SHIFT(pin)) & STM_MODER_MASK; @@ -69,7 +94,7 @@ stm_otyper_set(struct stm_gpio *gpio, int pin, vuint32_t value) {  			 ~(STM_OTYPER_MASK << STM_OTYPER_SHIFT(pin))) |  			value << STM_OTYPER_SHIFT(pin));  } -	 +  static inline uint32_t  stm_otyper_get(struct stm_gpio *gpio, int pin) {  	return (gpio->otyper >> STM_OTYPER_SHIFT(pin)) & STM_OTYPER_MASK; @@ -83,12 +108,21 @@ stm_otyper_get(struct stm_gpio *gpio, int pin) {  #define STM_OSPEEDR_40MHz		3  static inline void -stm_ospeedr_set(struct stm_gpio *gpio, int pin, vuint32_t value) { +stm_ospeedr_set(struct stm_gpio *gpio, int pin, uint32_t value) {  	gpio->ospeedr = ((gpio->ospeedr &  			~(STM_OSPEEDR_MASK << STM_OSPEEDR_SHIFT(pin))) |  		       value << STM_OSPEEDR_SHIFT(pin));  } -	 + +static inline void +stm_ospeedr_set_mask(struct stm_gpio *gpio, uint16_t mask, uint32_t value) { +	uint32_t	bits32 = stm_spread_mask(mask); +	uint32_t	mask32 = 3 * bits32; +	uint32_t	value32 = (value & 3) * bits32; + +	gpio->ospeedr = ((gpio->ospeedr & ~mask32) | value32); +} +  static inline uint32_t  stm_ospeedr_get(struct stm_gpio *gpio, int pin) {  	return (gpio->ospeedr >> STM_OSPEEDR_SHIFT(pin)) & STM_OSPEEDR_MASK; @@ -107,7 +141,16 @@ stm_pupdr_set(struct stm_gpio *gpio, int pin, uint32_t value) {  			~(STM_PUPDR_MASK << STM_PUPDR_SHIFT(pin))) |  		       value << STM_PUPDR_SHIFT(pin));  } -	 + +static inline void +stm_pupdr_set_mask(struct stm_gpio *gpio, uint16_t mask, uint32_t value) { +	uint32_t	bits32 = stm_spread_mask(mask); +	uint32_t	mask32 = 3 * bits32; +	uint32_t	value32 = (value & 3) * bits32; + +	gpio->pupdr = (gpio->pupdr & ~mask32) | value32; +} +  static inline uint32_t  stm_pupdr_get(struct stm_gpio *gpio, int pin) {  	return (gpio->pupdr >> STM_PUPDR_SHIFT(pin)) & STM_PUPDR_MASK; @@ -168,6 +211,12 @@ stm_gpio_set(struct stm_gpio *gpio, int pin, uint8_t value) {  }  static inline void +stm_gpio_set_mask(struct stm_gpio *gpio, uint16_t bits, uint16_t mask) { +	/* Use the bit set/reset register to do this atomically */ +	gpio->bsrr = ((uint32_t) (~bits & mask) << 16) | ((uint32_t) (bits & mask)); +} + +static inline void  stm_gpio_set_bits(struct stm_gpio *gpio, uint16_t bits) {  	gpio->bsrr = bits;  } @@ -518,7 +567,7 @@ extern struct stm_rcc stm_rcc;  #define  STM_RCC_CFGR_MCOPRE_DIV_4	2  #define  STM_RCC_CFGR_MCOPRE_DIV_8	3  #define  STM_RCC_CFGR_MCOPRE_DIV_16	4 -#define  STM_RCC_CFGR_MCOPRE_DIV_MASK	7 +#define  STM_RCC_CFGR_MCOPRE_MASK	7  #define STM_RCC_CFGR_MCOSEL	(24)  #define  STM_RCC_CFGR_MCOSEL_DISABLE	0 @@ -897,7 +946,11 @@ struct stm_nvic {  	vuint32_t	sc;		/* 0xc10 0xe000ed10 System Control Register */  	vuint32_t	cc;		/* 0xc14 0xe000ed14 Configuration Control Register */ -	uint8_t		_unusedc18[0xe00 - 0xc18]; +	vuint32_t	shpr7_4;	/* 0xc18 0xe000ed18 System Hander Priority Registers */ +	vuint32_t	shpr11_8;	/* 0xc1c */ +	vuint32_t	shpr15_12;	/* 0xc20 */ + +	uint8_t		_unusedc18[0xe00 - 0xc24];  	vuint32_t	stir;		/* 0xe00 */  }; @@ -1594,6 +1647,7 @@ extern struct stm_i2c stm_i2c1, stm_i2c2;  #define  STM_I2C_CR2_FREQ_4_MHZ		4  #define  STM_I2C_CR2_FREQ_8_MHZ		8  #define  STM_I2C_CR2_FREQ_16_MHZ	16 +#define  STM_I2C_CR2_FREQ_24_MHZ	24  #define  STM_I2C_CR2_FREQ_32_MHZ	32  #define  STM_I2C_CR2_FREQ_MASK		0x3f @@ -1740,6 +1794,12 @@ extern struct stm_tim234 stm_tim2, stm_tim3, stm_tim4;  #define  STM_TIM234_SMCR_SMS_EXTERNAL_CLOCK	7  #define  STM_TIM234_SMCR_SMS_MASK		7 +#define STM_TIM234_DIER_CC4IE		4 +#define STM_TIM234_DIER_CC3IE		3 +#define STM_TIM234_DIER_CC2IE		2 +#define STM_TIM234_DIER_CC1IE		1 +#define STM_TIM234_DIER_UIE		0 +  #define STM_TIM234_SR_CC4OF	12  #define STM_TIM234_SR_CC3OF	11  #define STM_TIM234_SR_CC2OF	10 @@ -1840,15 +1900,23 @@ extern struct stm_tim234 stm_tim2, stm_tim3, stm_tim4;  #define STM_TIM234_CCER_CC4NP	15  #define STM_TIM234_CCER_CC4P	13 +#define  STM_TIM234_CCER_CC4P_ACTIVE_HIGH	0 +#define  STM_TIM234_CCER_CC4P_ACTIVE_LOW	1  #define STM_TIM234_CCER_CC4E	12  #define STM_TIM234_CCER_CC3NP	11  #define STM_TIM234_CCER_CC3P	9 +#define  STM_TIM234_CCER_CC3P_ACTIVE_HIGH	0 +#define  STM_TIM234_CCER_CC3P_ACTIVE_LOW	1  #define STM_TIM234_CCER_CC3E	8  #define STM_TIM234_CCER_CC2NP	7  #define STM_TIM234_CCER_CC2P	5 +#define  STM_TIM234_CCER_CC2P_ACTIVE_HIGH	0 +#define  STM_TIM234_CCER_CC2P_ACTIVE_LOW	1  #define STM_TIM234_CCER_CC2E	4  #define STM_TIM234_CCER_CC1NP	3  #define STM_TIM234_CCER_CC1P	1 +#define  STM_TIM234_CCER_CC1P_ACTIVE_HIGH	0 +#define  STM_TIM234_CCER_CC1P_ACTIVE_LOW	1  #define STM_TIM234_CCER_CC1E	0  struct stm_usb { diff --git a/src/stmf0/Makefile-stmf0.defs b/src/stmf0/Makefile-stmf0.defs index f3296b69..f2c53499 100644 --- a/src/stmf0/Makefile-stmf0.defs +++ b/src/stmf0/Makefile-stmf0.defs @@ -4,7 +4,7 @@ endif  include $(TOPDIR)/Makedefs -vpath % $(TOPDIR)/stmf0:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR/aes):$(TOPDIR):$(TOPDIR)/math +vpath % $(TOPDIR)/stmf0:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR)/aes:$(TOPDIR):$(TOPDIR)/math:$(TOPDIR)/lisp  vpath make-altitude $(TOPDIR)/util  vpath make-kalman $(TOPDIR)/util  vpath kalman.5c $(TOPDIR)/kalman @@ -27,7 +27,10 @@ CC=$(ARM_CC)  WARN_FLAGS=-Wall -Wextra -Werror -Wcast-align -AO_CFLAGS=-I. -I$(TOPDIR)/stmf0 -I$(TOPDIR)/kernel -I$(TOPDIR)/drivers -I$(TOPDIR)/product -I$(TOPDIR) -I$(TOPDIR)/math $(PDCLIB_INCLUDES)  +AO_CFLAGS=-I. -I$(TOPDIR)/stmf0 -I$(TOPDIR)/kernel -I$(TOPDIR)/drivers \ +	-I$(TOPDIR)/product -I$(TOPDIR) -I$(TOPDIR)/math -I$(TOPDIR)/lisp \ +	$(PDCLIB_INCLUDES)  +  STMF0_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m0 -mthumb\  	-ffreestanding -nostdlib $(AO_CFLAGS) $(WARN_FLAGS) diff --git a/src/stmf0/altos-raw.ld b/src/stmf0/altos-raw.ld new file mode 100644 index 00000000..eb285e07 --- /dev/null +++ b/src/stmf0/altos-raw.ld @@ -0,0 +1,85 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +MEMORY { +	rom (rx) :   ORIGIN = 0x08000000, LENGTH = 32K +	ram (!w) :   ORIGIN = 0x20000000, LENGTH = 6k - 128 +	stack (!w) : ORIGIN = 0x20000000 + 6k - 128, LENGTH = 128 +} + +INCLUDE registers.ld + +EXTERN (stm_interrupt_vector) + +SECTIONS { +	/* +	 * Rom contents +	 */ + +	.interrupt : { +		__text_start__ = .; +		*(.interrupt)	/* Interrupt vectors */ +	} > rom + +	.text ORIGIN(rom) + 0x100 : { + +		/* Ick. What I want is to specify the +		 * addresses of some global constants so +		 * that I can find them across versions +		 * of the application. I can't figure out +		 * how to make gnu ld do that, so instead +		 * we just load the two files that include +		 * these defines in the right order here and +		 * expect things to 'just work'. Don't change +		 * the contents of those files, ok? +		 */ +		ao_romconfig.o(.romconfig*) +		ao_product.o(.romconfig*) + +		*(.text*)	/* Executable code */ +		*(.ARM.exidx* .gnu.linkonce.armexidx.*) +		*(.rodata*)	/* Constants */ + +	} > rom +	__text_end__ = .; + +	/* Data -- relocated to RAM, but written to ROM +	 */ +	.data : { +		__data_start__ = .; +		*(.data)	/* initialized data */ +		. = ALIGN(4); +		__data_end__ = .; +	} >ram AT>rom + +	.bss : { +		__bss_start__ = .; +		*(.bss) +		*(COMMON) +		. = ALIGN(4); +		__bss_end__ = .; +	} >ram + +	PROVIDE(end = .); + +	PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack)); +} + +ENTRY(start); + + diff --git a/src/stmf0/altos.ld b/src/stmf0/altos.ld index 8f8933c6..74fdf3ea 100644 --- a/src/stmf0/altos.ld +++ b/src/stmf0/altos.ld @@ -55,10 +55,16 @@ SECTIONS {  		ao_product.o(.romconfig*)  		*(.text*)	/* Executable code */ +	} > rom + +	.ARM.exidx : {  		*(.ARM.exidx* .gnu.linkonce.armexidx.*) -		*(.rodata*)	/* Constants */ +	} > rom +	.rodata : { +		*(.rodata*)	/* Constants */  	} > rom +  	__text_end__ = .;  	/* Boot data which must live at the start of ram so that diff --git a/src/stmf0/ao_adc_stm.c b/src/stmf0/ao_adc_stm.c new file mode 100644 index 00000000..2b23dc50 --- /dev/null +++ b/src/stmf0/ao_adc_stm.c @@ -0,0 +1,340 @@ +/* + * Copyright © 2015 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <ao.h> +#include <ao_data.h> + +#define AO_ADC_DEBUG	0 + +static uint8_t	ao_adc_ready; + +/* + * Callback from DMA ISR + * + * Mark time in ring, shut down DMA engine + */ +static void ao_adc_done(int index) +{ +	(void) index; +	/* Clear ISR bits */ +	stm_adc.isr = ((1 << STM_ADC_ISR_AWD) | +		       (1 << STM_ADC_ISR_OVR) | +		       (1 << STM_ADC_ISR_EOSEQ) | +		       (1 << STM_ADC_ISR_EOC)); + +	AO_DATA_PRESENT(AO_DATA_ADC); +	ao_dma_done_transfer(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1)); +	if (ao_data_present == AO_DATA_ALL) { +#if HAS_MS5607 +		ao_data_ring[ao_data_head].ms5607_raw = ao_ms5607_current; +#endif +#if HAS_MMA655X +		ao_data_ring[ao_data_head].mma655x = ao_mma655x_current; +#endif +#if HAS_HMC5883 +		ao_data_ring[ao_data_head].hmc5883 = ao_hmc5883_current; +#endif +#if HAS_MPU6000 +		ao_data_ring[ao_data_head].mpu6000 = ao_mpu6000_current; +#endif +		ao_data_ring[ao_data_head].tick = ao_tick_count; +		ao_data_head = ao_data_ring_next(ao_data_head); +		ao_wakeup((void *) &ao_data_head); +	} +	ao_adc_ready = 1; +} + +/* + * Start the ADC sequence using the DMA engine + */ +void +ao_adc_poll(void) +{ +	if (!ao_adc_ready) +		return; +	ao_adc_ready = 0; +	stm_adc.isr = 0; +	ao_dma_set_transfer(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1), +			    &stm_adc.dr, +			    (void *) (&ao_data_ring[ao_data_head].adc), +			    AO_NUM_ADC, +			    (0 << STM_DMA_CCR_MEM2MEM) | +			    (STM_DMA_CCR_PL_HIGH << STM_DMA_CCR_PL) | +			    (STM_DMA_CCR_MSIZE_16 << STM_DMA_CCR_MSIZE) | +			    (STM_DMA_CCR_PSIZE_16 << STM_DMA_CCR_PSIZE) | +			    (1 << STM_DMA_CCR_MINC) | +			    (0 << STM_DMA_CCR_PINC) | +			    (0 << STM_DMA_CCR_CIRC) | +			    (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) | +			    (1 << STM_DMA_CCR_TCIE)); +	ao_dma_set_isr(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1), ao_adc_done); +	ao_dma_start(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1)); + +	stm_adc.cr |= (1 << STM_ADC_CR_ADSTART); +} + +static void +ao_adc_dump(void) +{ +	struct ao_data	packet; + +	ao_data_get(&packet); +	AO_ADC_DUMP(&packet); +} + +#if AO_ADC_DEBUG +static void +ao_adc_one(void) +{ +	int		ch; +	uint16_t	value; + +	ao_cmd_decimal(); +	if (ao_cmd_status != ao_cmd_success) +		return; +	ch = ao_cmd_lex_i; +	if (ch < 0 || AO_NUM_ADC <= ch) { +		ao_cmd_status = ao_cmd_syntax_error; +		return; +	} + +	ao_timer_set_adc_interval(0); +	ao_delay(1); + +	printf("At top, data %u isr %04x cr %04x\n", stm_adc.dr, stm_adc.isr, stm_adc.cr); + +	if (stm_adc.cr & (1 << STM_ADC_CR_ADEN)) { +		printf("Disabling\n"); flush(); +		stm_adc.cr |= (1 << STM_ADC_CR_ADDIS); +		while (stm_adc.cr & (1 << STM_ADC_CR_ADDIS)) +			; +		printf("Disabled\n"); flush(); +	} + +	/* Turn off everything */ +	stm_adc.cr &= ~((1 << STM_ADC_CR_ADCAL) | +			(1 << STM_ADC_CR_ADSTP) | +			(1 << STM_ADC_CR_ADSTART) | +			(1 << STM_ADC_CR_ADEN)); + +	printf("After disable, ADC status %04x\n", stm_adc.cr); + +	/* Configure */ +	stm_adc.cfgr1 = ((0 << STM_ADC_CFGR1_AWDCH) |				  /* analog watchdog channel 0 */ +			 (0 << STM_ADC_CFGR1_AWDEN) |				  /* Disable analog watchdog */ +			 (0 << STM_ADC_CFGR1_AWDSGL) |				  /* analog watchdog on all channels */ +			 (0 << STM_ADC_CFGR1_DISCEN) |				  /* Not discontinuous mode. All channels converted with one trigger */ +			 (0 << STM_ADC_CFGR1_AUTOOFF) |				  /* Leave ADC running */ +			 (1 << STM_ADC_CFGR1_WAIT) |				  /* Wait for data to be read before next conversion */ +			 (0 << STM_ADC_CFGR1_CONT) |				  /* only one set of conversions per trigger */ +			 (1 << STM_ADC_CFGR1_OVRMOD) |				  /* overwrite on overrun */ +			 (STM_ADC_CFGR1_EXTEN_DISABLE << STM_ADC_CFGR1_EXTEN) |	  /* SW trigger */ +			 (0 << STM_ADC_CFGR1_ALIGN) |				  /* Align to LSB */ +			 (STM_ADC_CFGR1_RES_12 << STM_ADC_CFGR1_RES) |		  /* 12 bit resolution */ +			 (STM_ADC_CFGR1_SCANDIR_UP << STM_ADC_CFGR1_SCANDIR) |	  /* scan 0 .. n */ +			 (STM_ADC_CFGR1_DMACFG_ONESHOT << STM_ADC_CFGR1_DMACFG) | /* one set of conversions then stop */ +			 (0 << STM_ADC_CFGR1_DMAEN));				  /* disable DMA */ + +	stm_adc.chselr = (1 << ch); + +	/* Longest sample time */ +	stm_adc.smpr = STM_ADC_SMPR_SMP_41_5 << STM_ADC_SMPR_SMP; + +	printf("Before enable, ADC status %04x\n", stm_adc.cr); flush(); +	/* Enable */ +	stm_adc.cr |= (1 << STM_ADC_CR_ADEN); +	while ((stm_adc.isr & (1 << STM_ADC_ISR_ADRDY)) == 0) +		; + +	/* Start */ +	stm_adc.cr |= (1 << STM_ADC_CR_ADSTART); + +	/* Wait for conversion complete */ +	while (!(stm_adc.isr & (1 << STM_ADC_ISR_EOC))) +		; + +	value = stm_adc.dr; +	printf ("value %u, cr is %04x isr is %04x\n", +		value, stm_adc.cr, stm_adc.isr); + + +	/* Clear ISR bits */ +	stm_adc.isr = ((1 << STM_ADC_ISR_AWD) | +		       (1 << STM_ADC_ISR_OVR) | +		       (1 << STM_ADC_ISR_EOSEQ) | +		       (1 << STM_ADC_ISR_EOC)); +} +#endif + +__code struct ao_cmds ao_adc_cmds[] = { +	{ ao_adc_dump,	"a\0Display current ADC values" }, +#if AO_ADC_DEBUG +	{ ao_adc_one,	"A ch\0Display one ADC channel" }, +#endif +	{ 0, NULL }, +}; + +void +ao_adc_init(void) +{ +	uint32_t	chselr; + +	/* Reset ADC */ +	stm_rcc.apb2rstr |= (1 << STM_RCC_APB2RSTR_ADCRST); +	stm_rcc.apb2rstr &= ~(1 << STM_RCC_APB2RSTR_ADCRST); + +	/* Turn on ADC pins */ +	stm_rcc.ahbenr |= AO_ADC_RCC_AHBENR; + +#ifdef AO_ADC_PIN0_PORT +	stm_moder_set(AO_ADC_PIN0_PORT, AO_ADC_PIN0_PIN, STM_MODER_ANALOG); +	stm_pupdr_set(AO_ADC_PIN0_PORT, AO_ADC_PIN0_PIN, STM_PUPDR_NONE); +#endif +#ifdef AO_ADC_PIN1_PORT +	stm_moder_set(AO_ADC_PIN1_PORT, AO_ADC_PIN1_PIN, STM_MODER_ANALOG); +	stm_pupdr_set(AO_ADC_PIN1_PORT, AO_ADC_PIN1_PIN, STM_PUPDR_NONE); +#endif +#ifdef AO_ADC_PIN2_PORT +	stm_moder_set(AO_ADC_PIN2_PORT, AO_ADC_PIN2_PIN, STM_MODER_ANALOG); +	stm_pupdr_set(AO_ADC_PIN2_PORT, AO_ADC_PIN2_PIN, STM_PUPDR_NONE); +#endif +#ifdef AO_ADC_PIN3_PORT +	stm_moder_set(AO_ADC_PIN3_PORT, AO_ADC_PIN3_PIN, STM_MODER_ANALOG); +	stm_pupdr_set(AO_ADC_PIN3_PORT, AO_ADC_PIN3_PIN, STM_PUPDR_NONE); +#endif +#ifdef AO_ADC_PIN4_PORT +	stm_moder_set(AO_ADC_PIN4_PORT, AO_ADC_PIN4_PIN, STM_MODER_ANALOG); +	stm_pupdr_set(AO_ADC_PIN4_PORT, AO_ADC_PIN4_PIN, STM_PUPDR_NONE); +#endif +#ifdef AO_ADC_PIN5_PORT +	stm_moder_set(AO_ADC_PIN5_PORT, AO_ADC_PIN5_PIN, STM_MODER_ANALOG); +	stm_pupdr_set(AO_ADC_PIN5_PORT, AO_ADC_PIN5_PIN, STM_PUPDR_NONE); +#endif +#ifdef AO_ADC_PIN6_PORT +	stm_moder_set(AO_ADC_PIN6_PORT, AO_ADC_PIN6_PIN, STM_MODER_ANALOG); +	stm_pupdr_set(AO_ADC_PIN6_PORT, AO_ADC_PIN6_PIN, STM_PUPDR_NONE); +#endif +#ifdef AO_ADC_PIN7_PORT +	stm_moder_set(AO_ADC_PIN7_PORT, AO_ADC_PIN7_PIN, STM_MODER_ANALOG); +	stm_pupdr_set(AO_ADC_PIN7_PORT, AO_ADC_PIN7_PIN, STM_PUPDR_NONE); +#endif +#ifdef AO_ADC_PIN24_PORT +	#error "Too many ADC ports" +#endif + +	stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_ADCEN); + +	chselr = 0; +#if AO_NUM_ADC > 0 +	chselr |= (1 << AO_ADC_PIN0_CH); +#endif +#if AO_NUM_ADC > 1 +	chselr |= (1 << AO_ADC_PIN1_CH); +#endif +#if AO_NUM_ADC > 2 +	chselr |= (1 << AO_ADC_PIN2_CH); +#endif +#if AO_NUM_ADC > 3 +	chselr |= (1 << AO_ADC_PIN3_CH); +#endif +#if AO_NUM_ADC > 4 +	chselr |= (1 << AO_ADC_PIN4_CH); +#endif +#if AO_NUM_ADC > 5 +	chselr |= (1 << AO_ADC_PIN5_CH); +#endif +#if AO_NUM_ADC > 6 +	chselr |= (1 << AO_ADC_PIN6_CH); +#endif +#if AO_NUM_ADC > 7 +	chselr |= (1 << AO_ADC_PIN7_CH); +#endif +#if AO_NUM_ADC > 8 +#error Need more ADC defines +#endif + +	/* Wait for ADC to be idle */ +	while (stm_adc.cr & ((1 << STM_ADC_CR_ADCAL) | +			     (1 << STM_ADC_CR_ADDIS))) +		; + +	/* Disable */ +	if (stm_adc.cr & (1 << STM_ADC_CR_ADEN)) { +		stm_adc.cr |= (1 << STM_ADC_CR_ADDIS); +		while (stm_adc.cr & (1 << STM_ADC_CR_ADDIS)) +			; +	} + +	/* Turn off everything */ +	stm_adc.cr &= ~((1 << STM_ADC_CR_ADCAL) | +			(1 << STM_ADC_CR_ADSTP) | +			(1 << STM_ADC_CR_ADSTART) | +			(1 << STM_ADC_CR_ADEN)); + +	/* Configure */ +	stm_adc.cfgr1 = ((0 << STM_ADC_CFGR1_AWDCH) |				  /* analog watchdog channel 0 */ +			 (0 << STM_ADC_CFGR1_AWDEN) |				  /* Disable analog watchdog */ +			 (0 << STM_ADC_CFGR1_AWDSGL) |				  /* analog watchdog on all channels */ +			 (0 << STM_ADC_CFGR1_DISCEN) |				  /* Not discontinuous mode. All channels converted with one trigger */ +			 (0 << STM_ADC_CFGR1_AUTOOFF) |				  /* Leave ADC running */ +			 (1 << STM_ADC_CFGR1_WAIT) |				  /* Wait for data to be read before next conversion */ +			 (0 << STM_ADC_CFGR1_CONT) |				  /* only one set of conversions per trigger */ +			 (1 << STM_ADC_CFGR1_OVRMOD) |				  /* overwrite on overrun */ +			 (STM_ADC_CFGR1_EXTEN_DISABLE << STM_ADC_CFGR1_EXTEN) |	  /* SW trigger */ +			 (0 << STM_ADC_CFGR1_ALIGN) |				  /* Align to LSB */ +			 (STM_ADC_CFGR1_RES_12 << STM_ADC_CFGR1_RES) |		  /* 12 bit resolution */ +			 (STM_ADC_CFGR1_SCANDIR_UP << STM_ADC_CFGR1_SCANDIR) |	  /* scan 0 .. n */ +			 (STM_ADC_CFGR1_DMACFG_ONESHOT << STM_ADC_CFGR1_DMACFG) | /* one set of conversions then stop */ +			 (1 << STM_ADC_CFGR1_DMAEN));				  /* enable DMA */ + +	/* Set the clock */ +	stm_adc.cfgr2 = STM_ADC_CFGR2_CKMODE_PCLK_2 << STM_ADC_CFGR2_CKMODE; + +	/* Shortest sample time */ +	stm_adc.smpr = STM_ADC_SMPR_SMP_71_5 << STM_ADC_SMPR_SMP; + +	stm_adc.chselr = chselr; + +	stm_adc.ccr = ((0 << STM_ADC_CCR_VBATEN) | +		       (0 << STM_ADC_CCR_TSEN) | +		       (0 << STM_ADC_CCR_VREFEN)); + +	/* Calibrate */ +	stm_adc.cr |= (1 << STM_ADC_CR_ADCAL); +	while ((stm_adc.cr & (1 << STM_ADC_CR_ADCAL)) != 0) +		; + +	/* Enable */ +	stm_adc.cr |= (1 << STM_ADC_CR_ADEN); +	while ((stm_adc.isr & (1 << STM_ADC_ISR_ADRDY)) == 0) +		; + +	/* Clear any stale status bits */ +	stm_adc.isr = 0; + +	/* Turn on syscfg */ +	stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SYSCFGCOMPEN); + +	/* Set ADC to use DMA channel 1 (option 1) */ +	stm_syscfg.cfgr1 &= ~(1 << STM_SYSCFG_CFGR1_ADC_DMA_RMP); + +	ao_dma_alloc(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1)); + +	ao_cmd_register(&ao_adc_cmds[0]); + +	ao_adc_ready = 1; +} diff --git a/src/stmf0/ao_arch.h b/src/stmf0/ao_arch.h index a36482b6..c5f451f5 100644 --- a/src/stmf0/ao_arch.h +++ b/src/stmf0/ao_arch.h @@ -144,10 +144,15 @@ ao_adc_init();  /* ADC maximum reported value */  #define AO_ADC_MAX			4095 +#ifndef HAS_BOOT_LOADER +#define HAS_BOOT_LOADER			1 +#endif + +#if HAS_BOOT_LOADER  #define AO_BOOT_APPLICATION_BASE	((uint32_t *) 0x08001000)  #define AO_BOOT_APPLICATION_BOUND	((uint32_t *) (0x08000000 + stm_flash_size()))  #define AO_BOOT_LOADER_BASE		((uint32_t *) 0x08000000) -#define HAS_BOOT_LOADER			1 +#endif  #endif /* _AO_ARCH_H_ */ diff --git a/src/stmf0/ao_arch_funcs.h b/src/stmf0/ao_arch_funcs.h index 0cb0e43d..c38ce41a 100644 --- a/src/stmf0/ao_arch_funcs.h +++ b/src/stmf0/ao_arch_funcs.h @@ -314,7 +314,18 @@ struct ao_stm_usart {  	struct ao_fifo		rx_fifo;  	struct ao_fifo		tx_fifo;  	struct stm_usart	*reg; -	uint8_t			tx_started; +	uint8_t			tx_running; +	uint8_t			draining; +#if HAS_SERIAL_SW_FLOW +	/* RTS - 0 if we have FIFO space, 1 if not +	 * CTS - 0 if we can send, 0 if not +	 */ +	struct stm_gpio		*gpio_rts; +	struct stm_gpio		*gpio_cts; +	uint8_t			pin_rts; +	uint8_t			pin_cts; +	uint8_t			rts; +#endif  };  #if HAS_SERIAL_1 diff --git a/src/stmf0/ao_beep_stm.c b/src/stmf0/ao_beep_stm.c new file mode 100644 index 00000000..610f4a31 --- /dev/null +++ b/src/stmf0/ao_beep_stm.c @@ -0,0 +1,389 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" + +#ifndef BEEPER_CHANNEL +#error BEEPER_CHANNEL undefined +#endif + +#ifndef BEEPER_TIMER +#define BEEPER_TIMER	1 +#endif + +#if BEEPER_TIMER == 1 +#define timer stm_tim1 +#define STM_RCC_TIMER STM_RCC_APB2ENR_TIM1EN +#define stm_rcc_enr stm_rcc.apb2enr +#endif + +#if BEEPER_TIMER == 2 +#define timer stm_tim2 +#define STM_RCC_TIMER STM_RCC_APB1ENR_TIM2EN +#define stm_rcc_enr stm_rcc.apb1enr +#endif + +#if BEEPER_TIMER == 3 +#define timer stm_tim3 +#define STM_RCC_TIMER STM_RCC_APB1ENR_TIM3EN +#define stm_rcc_enr stm_rcc.apb1enr +#endif + +#ifndef timer +#error BEEPER_TIMER invalid +#endif + +static inline void +disable(void) +{ +	timer.cr1 = 0; +#if BEEPER_TIMER == 1 +	timer.bdtr = 0; +#endif +	stm_rcc_enr &= ~(1 << STM_RCC_TIMER); + +	/* Disconnect the timer from the pin */ +	stm_afr_set(BEEPER_PORT, BEEPER_PIN, STM_AFR_NONE); +} + +void +ao_beep(uint8_t beep) +{ +	if (beep == 0) { +		disable(); +	} else { +		stm_rcc_enr |= (1 << STM_RCC_TIMER); + +#if BEEPER_TIMER == 1 +		/* Master output enable */ +		stm_tim1.bdtr = (1 << STM_TIM1_BDTR_MOE); + +		stm_tim1.cr2 = ((0 << STM_TIM1_CR2_TI1S) | +				(STM_TIM1_CR2_MMS_RESET << STM_TIM1_CR2_MMS) | +				(0 << STM_TIM1_CR2_CCDS)); + +		/* Set prescaler to match cc1111 clocks +		 */ +		stm_tim1.psc = AO_TIM_CLK / 750000; + +		/* 1. Select the counter clock (internal, external, prescaler). +		 * +		 * Setting SMCR to zero means use the internal clock +		 */ + +		stm_tim1.smcr = 0; + +		/* 2. Write the desired data in the TIMx_ARR and TIMx_CCRx registers. */ +		stm_tim1.arr = beep; +		stm_tim1.ccr1 = beep; + +		/* 3. Set the CCxIE and/or CCxDE bits if an interrupt and/or a +		 * DMA request is to be generated. +		 */ +		/* don't want this */ + +		/* 4. Select the output mode. For example, you must write +		 *  OCxM=011, OCxPE=0, CCxP=0 and CCxE=1 to toggle OCx output +		 *  pin when CNT matches CCRx, CCRx preload is not used, OCx +		 *  is enabled and active high. +		 */ + +#if BEEPER_CHANNEL == 1 +		stm_tim1.ccmr1 = ((0 << STM_TIM1_CCMR1_OC2CE) | +				  (STM_TIM1_CCMR_OCM_FROZEN << STM_TIM1_CCMR1_OC2M) | +				  (0 << STM_TIM1_CCMR1_OC2PE) | +				  (0 << STM_TIM1_CCMR1_OC2FE) | +				  (STM_TIM1_CCMR_CCS_OUTPUT << STM_TIM1_CCMR1_CC2S) | + +				  (0 << STM_TIM1_CCMR1_OC1CE) | +				  (STM_TIM1_CCMR_OCM_TOGGLE << STM_TIM1_CCMR1_OC1M) | +				  (0 << STM_TIM1_CCMR1_OC1PE) | +				  (0 << STM_TIM1_CCMR1_OC1FE) | +				  (STM_TIM1_CCMR_CCS_OUTPUT << STM_TIM1_CCMR1_CC1S)); + +		stm_tim1.ccer = ((0 << STM_TIM1_CCER_CC4P) | +				 (0 << STM_TIM1_CCER_CC4E) | +				 (0 << STM_TIM1_CCER_CC3NP) | +				 (0 << STM_TIM1_CCER_CC3NE) | +				 (0 << STM_TIM1_CCER_CC3P) | +				 (0 << STM_TIM1_CCER_CC3E) | +				 (0 << STM_TIM1_CCER_CC2NP) | +				 (0 << STM_TIM1_CCER_CC2NE) | +				 (0 << STM_TIM1_CCER_CC2P) | +				 (0 << STM_TIM1_CCER_CC2E) | +				 (0 << STM_TIM1_CCER_CC1NE) | +				 (0 << STM_TIM1_CCER_CC1P) | +				 (1 << STM_TIM1_CCER_CC1E)); +#endif +#if BEEPER_CHANNEL == 2 +		stm_tim1.ccmr1 = ((0 << STM_TIM1_CCMR1_OC2CE) | +				  (STM_TIM1_CCMR_OCM_TOGGLE << STM_TIM1_CCMR1_OC2M) | +				  (0 << STM_TIM1_CCMR1_OC2PE) | +				  (0 << STM_TIM1_CCMR1_OC2FE) | +				  (STM_TIM1_CCMR_CCS_OUTPUT << STM_TIM1_CCMR1_CC2S) | + +				  (0 << STM_TIM1_CCMR1_OC1CE) | +				  (STM_TIM1_CCMR_OCM_FROZEN << STM_TIM1_CCMR1_OC1M) | +				  (0 << STM_TIM1_CCMR1_OC1PE) | +				  (0 << STM_TIM1_CCMR1_OC1FE) | +				  (STM_TIM1_CCMR_CCS_OUTPUT << STM_TIM1_CCMR1_CC1S)); + +		stm_tim1.ccer = ((0 << STM_TIM1_CCER_CC4P) | +				 (0 << STM_TIM1_CCER_CC4E) | +				 (0 << STM_TIM1_CCER_CC3NP) | +				 (0 << STM_TIM1_CCER_CC3NE) | +				 (0 << STM_TIM1_CCER_CC3P) | +				 (0 << STM_TIM1_CCER_CC3E) | +				 (0 << STM_TIM1_CCER_CC2NP) | +				 (0 << STM_TIM1_CCER_CC2NE) | +				 (0 << STM_TIM1_CCER_CC2P) | +				 (1 << STM_TIM1_CCER_CC2E) | +				 (0 << STM_TIM1_CCER_CC1NE) | +				 (0 << STM_TIM1_CCER_CC1P) | +				 (0 << STM_TIM1_CCER_CC1E)); +#endif +#if BEEPER_CHANNEL == 3 +		stm_tim1.ccmr2 = ((0 << STM_TIM1_CCMR2_OC4CE) | +				  (STM_TIM1_CCMR_OCM_FROZEN << STM_TIM1_CCMR2_OC4M) | +				  (0 << STM_TIM1_CCMR2_OC4PE) | +				  (0 << STM_TIM1_CCMR2_OC4FE) | +				  (STM_TIM1_CCMR_CCS_OUTPUT << STM_TIM1_CCMR2_CC4S) | + +				  (0 << STM_TIM1_CCMR2_OC3CE) | +				  (STM_TIM1_CCMR_OCM_TOGGLE << STM_TIM1_CCMR2_OC3M) | +				  (0 << STM_TIM1_CCMR2_OC3PE) | +				  (0 << STM_TIM1_CCMR2_OC3FE) | +				  (STM_TIM1_CCMR_CCS_OUTPUT << STM_TIM1_CCMR2_CC3S)); + +		stm_tim1.ccer = ((0 << STM_TIM1_CCER_CC4P) | +				 (0 << STM_TIM1_CCER_CC4E) | +				 (0 << STM_TIM1_CCER_CC3NP) | +				 (0 << STM_TIM1_CCER_CC3NE) | +				 (0 << STM_TIM1_CCER_CC3P) | +				 (1 << STM_TIM1_CCER_CC3E) | +				 (0 << STM_TIM1_CCER_CC2NP) | +				 (0 << STM_TIM1_CCER_CC2NE) | +				 (0 << STM_TIM1_CCER_CC2P) | +				 (0 << STM_TIM1_CCER_CC2E) | +				 (0 << STM_TIM1_CCER_CC1NE) | +				 (0 << STM_TIM1_CCER_CC1P) | +				 (0 << STM_TIM1_CCER_CC1E)); +#endif +#if BEEPER_CHANNEL == 4 +		stm_tim1.ccmr2 = ((0 << STM_TIM1_CCMR2_OC4CE) | +				  (STM_TIM1_CCMR2_OC4M_TOGGLE << STM_TIM1_CCMR2_OC4M) | +				  (0 << STM_TIM1_CCMR2_OC4PE) | +				  (0 << STM_TIM1_CCMR2_OC4FE) | +				  (STM_TIM1_CCMR2_CC4S_OUTPUT << STM_TIM1_CCMR2_CC4S) | + +				  (0 << STM_TIM1_CCMR2_OC3CE) | +				  (STM_TIM1_CCMR2_OC3M_FROZEN << STM_TIM1_CCMR2_OC3M) | +				  (0 << STM_TIM1_CCMR2_OC3PE) | +				  (0 << STM_TIM1_CCMR2_OC3FE) | +				  (STM_TIM1_CCMR2_CC3S_OUTPUT << STM_TIM1_CCMR2_CC3S)); + +		stm_tim1.ccer = ((0 << STM_TIM1_CCER_CC4NP) | +				 (0 << STM_TIM1_CCER_CC4P) | +				 (1 << STM_TIM1_CCER_CC4E) | +				 (0 << STM_TIM1_CCER_CC3NP) | +				 (0 << STM_TIM1_CCER_CC3P) | +				 (0 << STM_TIM1_CCER_CC3E) | +				 (0 << STM_TIM1_CCER_CC2NP) | +				 (0 << STM_TIM1_CCER_CC2P) | +				 (0 << STM_TIM1_CCER_CC2E) | +				 (0 << STM_TIM1_CCER_CC1NP) | +				 (0 << STM_TIM1_CCER_CC1P) | +				 (0 << STM_TIM1_CCER_CC1E)); +#endif +		/* 5. Enable the counter by setting the CEN bit in the TIMx_CR1 register. */ + +		stm_tim1.cr1 = ((STM_TIM1_CR1_CKD_1 << STM_TIM1_CR1_CKD) | +				(0 << STM_TIM1_CR1_ARPE) | +				(STM_TIM1_CR1_CMS_EDGE << STM_TIM1_CR1_CMS) | +				(0 << STM_TIM1_CR1_DIR) | +				(0 << STM_TIM1_CR1_OPM) | +				(0 << STM_TIM1_CR1_URS) | +				(0 << STM_TIM1_CR1_UDIS) | +				(1 << STM_TIM1_CR1_CEN)); + +		/* Update the values */ +		stm_tim1.egr = (1 << STM_TIM1_EGR_UG); +#endif +#if BEEPER_TIMER == 2 || BEEPER_TIMER == 3 + +		timer.cr2 = ((0 << STM_TIM23_CR2_TI1S) | +			     (STM_TIM23_CR2_MMS_RESET << STM_TIM23_CR2_MMS) | +			     (0 << STM_TIM23_CR2_CCDS)); + +		/* Set prescaler to match cc1111 clocks +		 */ +		timer.psc = AO_TIM_CLK / 750000; + +		/* 1. Select the counter clock (internal, external, prescaler). +		 * +		 * Setting SMCR to zero means use the internal clock +		 */ + +		timer.smcr = 0; + +		/* 2. Write the desired data in the TIMx_ARR and TIMx_CCRx registers. */ +		timer.arr = beep; +		timer.ccr1 = beep; + +		/* 3. Set the CCxIE and/or CCxDE bits if an interrupt and/or a +		 * DMA request is to be generated. +		 */ +		/* don't want this */ + +		/* 4. Select the output mode. For example, you must write +		 *  OCxM=011, OCxPE=0, CCxP=0 and CCxE=1 to toggle OCx output +		 *  pin when CNT matches CCRx, CCRx preload is not used, OCx +		 *  is enabled and active high. +		 */ + +#if BEEPER_CHANNEL == 1 +		timer.ccmr1 = ((0 << STM_TIM23_CCMR1_OC2CE) | +			       (STM_TIM23_CCMR1_OC2M_FROZEN << STM_TIM23_CCMR1_OC2M) | +			       (0 << STM_TIM23_CCMR1_OC2PE) | +			       (0 << STM_TIM23_CCMR1_OC2FE) | +			       (STM_TIM23_CCMR1_CC2S_OUTPUT << STM_TIM23_CCMR1_CC2S) | + +			       (0 << STM_TIM23_CCMR1_OC1CE) | +			       (STM_TIM23_CCMR1_OC1M_TOGGLE << STM_TIM23_CCMR1_OC1M) | +			       (0 << STM_TIM23_CCMR1_OC1PE) | +			       (0 << STM_TIM23_CCMR1_OC1FE) | +			       (STM_TIM23_CCMR1_CC1S_OUTPUT << STM_TIM23_CCMR1_CC1S)); + +		timer.ccer = ((0 << STM_TIM23_CCER_CC4P) | +			      (0 << STM_TIM23_CCER_CC4E) | +			      (0 << STM_TIM23_CCER_CC3NP) | +			      (0 << STM_TIM23_CCER_CC3P) | +			      (0 << STM_TIM23_CCER_CC3E) | +			      (0 << STM_TIM23_CCER_CC2NP) | +			      (0 << STM_TIM23_CCER_CC2P) | +			      (0 << STM_TIM23_CCER_CC2E) | +			      (0 << STM_TIM23_CCER_CC1P) | +			      (1 << STM_TIM23_CCER_CC1E)); +#endif +#if BEEPER_CHANNEL == 2 +		timer.ccmr1 = ((0 << STM_TIM23_CCMR1_OC2CE) | +			       (STM_TIM23_CCMR1_OC2M_TOGGLE << STM_TIM23_CCMR1_OC2M) | +			       (0 << STM_TIM23_CCMR1_OC2PE) | +			       (0 << STM_TIM23_CCMR1_OC2FE) | +			       (STM_TIM23_CCMR1_CC2S_OUTPUT << STM_TIM23_CCMR1_CC2S) | + +			       (0 << STM_TIM23_CCMR1_OC1CE) | +			       (STM_TIM23_CCMR1_OC1M_FROZEN << STM_TIM23_CCMR1_OC1M) | +			       (0 << STM_TIM23_CCMR1_OC1PE) | +			       (0 << STM_TIM23_CCMR1_OC1FE) | +			       (STM_TIM23_CCMR1_CC1S_OUTPUT << STM_TIM23_CCMR1_CC1S)); + +		timer.ccer = ((0 << STM_TIM23_CCER_CC4P) | +			      (0 << STM_TIM23_CCER_CC4E) | +			      (0 << STM_TIM23_CCER_CC3NP) | +			      (0 << STM_TIM23_CCER_CC3P) | +			      (0 << STM_TIM23_CCER_CC3E) | +			      (0 << STM_TIM23_CCER_CC2NP) | +			      (0 << STM_TIM23_CCER_CC2P) | +			      (1 << STM_TIM23_CCER_CC2E) | +			      (0 << STM_TIM23_CCER_CC1P) | +			      (0 << STM_TIM23_CCER_CC1E)); +#endif +#if BEEPER_CHANNEL == 3 +		timer.ccmr2 = ((0 << STM_TIM23_CCMR2_OC4CE) | +			       (STM_TIM23_CCMR2_OC4M_FROZEN << STM_TIM23_CCMR2_OC4M) | +			       (0 << STM_TIM23_CCMR2_OC4PE) | +			       (0 << STM_TIM23_CCMR2_OC4FE) | +			       (STM_TIM23_CCMR2_CC4S_OUTPUT << STM_TIM23_CCMR2_CC4S) | + +			       (0 << STM_TIM23_CCMR2_OC3CE) | +			       (STM_TIM23_CCMR2_OC3M_TOGGLE << STM_TIM23_CCMR2_OC3M) | +			       (0 << STM_TIM23_CCMR2_OC3PE) | +			       (0 << STM_TIM23_CCMR2_OC3FE) | +			       (STM_TIM23_CCMR2_CC3S_OUTPUT << STM_TIM23_CCMR2_CC3S)); + +		timer.ccer = ((0 << STM_TIM23_CCER_CC4P) | +			      (0 << STM_TIM23_CCER_CC4E) | +			      (0 << STM_TIM23_CCER_CC3NP) | +			      (0 << STM_TIM23_CCER_CC3P) | +			      (1 << STM_TIM23_CCER_CC3E) | +			      (0 << STM_TIM23_CCER_CC2NP) | +			      (0 << STM_TIM23_CCER_CC2P) | +			      (0 << STM_TIM23_CCER_CC2E) | +			      (0 << STM_TIM23_CCER_CC1P) | +			      (0 << STM_TIM23_CCER_CC1E)); +#endif +#if BEEPER_CHANNEL == 4 +		timer.ccmr2 = ((0 << STM_TIM23_CCMR2_OC4CE) | +			       (STM_TIM23_CCMR2_OC4M_TOGGLE << STM_TIM23_CCMR2_OC4M) | +			       (0 << STM_TIM23_CCMR2_OC4PE) | +			       (0 << STM_TIM23_CCMR2_OC4FE) | +			       (STM_TIM23_CCMR2_CC4S_OUTPUT << STM_TIM23_CCMR2_CC4S) | + +			       (0 << STM_TIM23_CCMR2_OC3CE) | +			       (STM_TIM23_CCMR2_OC3M_FROZEN << STM_TIM23_CCMR2_OC3M) | +			       (0 << STM_TIM23_CCMR2_OC3PE) | +			       (0 << STM_TIM23_CCMR2_OC3FE) | +			       (STM_TIM23_CCMR2_CC3S_OUTPUT << STM_TIM23_CCMR2_CC3S)); + +		timer.ccer = ((0 << STM_TIM23_CCER_CC4P) | +			      (1 << STM_TIM23_CCER_CC4E) | +			      (0 << STM_TIM23_CCER_CC3NP) | +			      (0 << STM_TIM23_CCER_CC3P) | +			      (0 << STM_TIM23_CCER_CC3E) | +			      (0 << STM_TIM23_CCER_CC2NP) | +			      (0 << STM_TIM23_CCER_CC2P) | +			      (0 << STM_TIM23_CCER_CC2E) | +			      (0 << STM_TIM23_CCER_CC1P) | +			      (0 << STM_TIM23_CCER_CC1E)); +#endif +		/* 5. Enable the counter by setting the CEN bit in the TIMx_CR1 register. */ + +		timer.cr1 = ((STM_TIM23_CR1_CKD_1 << STM_TIM23_CR1_CKD) | +			     (0 << STM_TIM23_CR1_ARPE) | +			     (STM_TIM23_CR1_CMS_EDGE << STM_TIM23_CR1_CMS) | +			     (0 << STM_TIM23_CR1_DIR) | +			     (0 << STM_TIM23_CR1_OPM) | +			     (0 << STM_TIM23_CR1_URS) | +			     (0 << STM_TIM23_CR1_UDIS) | +			     (1 << STM_TIM23_CR1_CEN)); + +		/* Update the values */ +		timer.egr = (1 << STM_TIM23_EGR_UG); + +		/* Hook the timer up to the beeper pin */ +		stm_afr_set(BEEPER_PORT, BEEPER_PIN, STM_AFR_AF2); +#endif +	} +} + +void +ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant +{ +	ao_beep(beep); +	ao_delay(ticks); +	ao_beep(0); +} + +void +ao_beep_init(void) +{ +	ao_enable_output(BEEPER_PORT, BEEPER_PIN, BEEPER, 0); + +	/* Leave the timer off until requested */ +	stm_rcc_enr &= ~(1 << STM_RCC_TIMER); +} diff --git a/src/stmf0/ao_crc.h b/src/stmf0/ao_crc.h index 7acc6f9c..b6d91023 100644 --- a/src/stmf0/ao_crc.h +++ b/src/stmf0/ao_crc.h @@ -35,7 +35,8 @@  static inline uint16_t  ao_crc_in_32_out_16(uint32_t v) {  	stm_crc.dr.u32 = v; -	return stm_crc.dr.u16; +	v = stm_crc.dr.u32; +	return v ^ (v >> 16);  }  static inline uint16_t diff --git a/src/stmf0/ao_flash_stm.c b/src/stmf0/ao_flash_stm.c index 2aeff388..2d57eea7 100644 --- a/src/stmf0/ao_flash_stm.c +++ b/src/stmf0/ao_flash_stm.c @@ -19,6 +19,12 @@  #include <ao.h>  #include <ao_flash.h> +/* Note that the HSI clock must be running for this code to work. + * Also, special care must be taken with the linker to ensure that the + * functions marked 'ramtext' land in ram and not rom. An example of that + * can be found in altos-loader.ld + */ +  static uint8_t  ao_flash_is_locked(void)  { @@ -44,12 +50,7 @@ ao_flash_lock(void)  	stm_flash.cr |= (1 << STM_FLASH_CR_LOCK);  } -static void -ao_flash_wait_bsy(void) -{ -	while (stm_flash.sr & (1 << STM_FLASH_SR_BSY)) -		; -} +#define ao_flash_wait_bsy() do { while (stm_flash.sr & (1 << STM_FLASH_SR_BSY)); } while (0)  static void __attribute__ ((section(".ramtext"),noinline))  _ao_flash_erase_page(uint32_t *page) diff --git a/src/stmf0/ao_interrupt.c b/src/stmf0/ao_interrupt.c index 79412483..fcd330f1 100644 --- a/src/stmf0/ao_interrupt.c +++ b/src/stmf0/ao_interrupt.c @@ -26,9 +26,11 @@  #define IS_FLASH_LOADER	0  #endif +#ifndef RELOCATE_INTERRUPT  #if !IS_FLASH_LOADER  #define RELOCATE_INTERRUPT	1  #endif +#endif  extern void main(void);  extern char __stack__; diff --git a/src/stmf0/ao_serial_stm.c b/src/stmf0/ao_serial_stm.c new file mode 100644 index 00000000..30b0dbd2 --- /dev/null +++ b/src/stmf0/ao_serial_stm.c @@ -0,0 +1,500 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <ao.h> +#include <ao_exti.h> + +void +ao_debug_out(char c) +{ +	if (c == '\n') +		ao_debug_out('\r'); +	while (!(stm_usart1.isr & (1 << STM_USART_ISR_TXE))); +	stm_usart1.tdr = c; +} + +static int +_ao_usart_tx_start(struct ao_stm_usart *usart) +{ +	if (!ao_fifo_empty(usart->tx_fifo)) { +#if HAS_SERIAL_SW_FLOW +		if (usart->gpio_cts && ao_gpio_get(usart->gpio_cts, usart->pin_cts, foo) == 1) { +			ao_exti_enable(usart->gpio_cts, usart->pin_cts); +			return 0; +		} +#endif +		if (usart->reg->isr & (1 << STM_USART_ISR_TXE)) +		{ +			usart->tx_running = 1; +			usart->reg->cr1 |= (1 << STM_USART_CR1_TXEIE) | (1 << STM_USART_CR1_TCIE); +			ao_fifo_remove(usart->tx_fifo, usart->reg->tdr); +			ao_wakeup(&usart->tx_fifo); +			return 1; +		} +	} +	return 0; +} + +#if HAS_SERIAL_SW_FLOW +static void +_ao_usart_cts(struct ao_stm_usart *usart) +{ +	if (_ao_usart_tx_start(usart)) +		ao_exti_disable(usart->gpio_cts, usart->pin_cts); +} +#endif + +static void +_ao_usart_rx(struct ao_stm_usart *usart, int stdin) +{ +	if (usart->reg->isr & (1 << STM_USART_ISR_RXNE)) { +		usart->reg->icr = (1 << STM_USART_ICR_ORECF); +		if (!ao_fifo_full(usart->rx_fifo)) { +			ao_fifo_insert(usart->rx_fifo, usart->reg->rdr); +			ao_wakeup(&usart->rx_fifo); +			if (stdin) +				ao_wakeup(&ao_stdin_ready); +#if HAS_SERIAL_SW_FLOW +			/* If the fifo is nearly full, turn off RTS and wait +			 * for it to drain a bunch +			 */ +			if (usart->gpio_rts && ao_fifo_mostly(usart->rx_fifo)) { +				ao_gpio_set(usart->gpio_rts, usart->pin_rts, usart->pin_rts, 1); +				usart->rts = 0; +			} +#endif +		} else { +			usart->reg->cr1 &= ~(1 << STM_USART_CR1_RXNEIE); +		} +	} +} + +static void +ao_usart_isr(struct ao_stm_usart *usart, int stdin) +{ +	_ao_usart_rx(usart, stdin); + +	if (!_ao_usart_tx_start(usart)) +		usart->reg->cr1 &= ~(1<< STM_USART_CR1_TXEIE); + +	if (usart->reg->isr & (1 << STM_USART_ISR_TC)) { +		usart->tx_running = 0; +		usart->reg->cr1 &= ~(1 << STM_USART_CR1_TCIE); +		if (usart->draining) { +			usart->draining = 0; +			ao_wakeup(&usart->tx_fifo); +		} +	} +} + +static int +_ao_usart_pollchar(struct ao_stm_usart *usart) +{ +	int	c; + +	if (ao_fifo_empty(usart->rx_fifo)) +		c = AO_READ_AGAIN; +	else { +		uint8_t	u; +		ao_fifo_remove(usart->rx_fifo,u); +		if ((usart->reg->cr1 & (1 << STM_USART_CR1_RXNEIE)) == 0) { +			if (ao_fifo_barely(usart->rx_fifo)) +				usart->reg->cr1 |= (1 << STM_USART_CR1_RXNEIE); +		} +#if HAS_SERIAL_SW_FLOW +		/* If we've cleared RTS, check if there's space now and turn it back on */ +		if (usart->gpio_rts && usart->rts == 0 && ao_fifo_barely(usart->rx_fifo)) { +			ao_gpio_set(usart->gpio_rts, usart->pin_rts, foo, 0); +			usart->rts = 1; +		} +#endif +		c = u; +	} +	return c; +} + +static char +ao_usart_getchar(struct ao_stm_usart *usart) +{ +	int c; +	ao_arch_block_interrupts(); +	while ((c = _ao_usart_pollchar(usart)) == AO_READ_AGAIN) +		ao_sleep(&usart->rx_fifo); +	ao_arch_release_interrupts(); +	return (char) c; +} + +static inline uint8_t +_ao_usart_sleep_for(struct ao_stm_usart *usart, uint16_t timeout) +{ +	return ao_sleep_for(&usart->rx_fifo, timeout); +} + +static void +ao_usart_putchar(struct ao_stm_usart *usart, char c) +{ +	ao_arch_block_interrupts(); +	while (ao_fifo_full(usart->tx_fifo)) +		ao_sleep(&usart->tx_fifo); +	ao_fifo_insert(usart->tx_fifo, c); +	_ao_usart_tx_start(usart); +	ao_arch_release_interrupts(); +} + +static void +ao_usart_drain(struct ao_stm_usart *usart) +{ +	ao_arch_block_interrupts(); +	while (!ao_fifo_empty(usart->tx_fifo) || usart->tx_running) { +		usart->draining = 1; +		ao_sleep(&usart->tx_fifo); +	} +	ao_arch_release_interrupts(); +} + +static const struct { +	uint32_t brr; +} ao_usart_speeds[] = { +	[AO_SERIAL_SPEED_4800] = { +		AO_PCLK / 4800 +	}, +	[AO_SERIAL_SPEED_9600] = { +		AO_PCLK / 9600 +	}, +	[AO_SERIAL_SPEED_19200] = { +		AO_PCLK / 19200 +	}, +	[AO_SERIAL_SPEED_57600] = { +		AO_PCLK / 57600 +	}, +	[AO_SERIAL_SPEED_115200] = { +		AO_PCLK / 115200 +	}, +}; + +static void +ao_usart_set_speed(struct ao_stm_usart *usart, uint8_t speed) +{ +	if (speed > AO_SERIAL_SPEED_115200) +		return; +	usart->reg->brr = ao_usart_speeds[speed].brr; +} + +static void +ao_usart_init(struct ao_stm_usart *usart) +{ +	usart->reg->cr1 = ((0 << STM_USART_CR1_M1) | +			   (0 << STM_USART_CR1_EOBIE) | +			   (0 << STM_USART_CR1_RTOIE) | +			   (0 << STM_USART_CR1_DEAT) | +			   (0 << STM_USART_CR1_DEDT) | +			   (0 << STM_USART_CR1_OVER8) | +			   (0 << STM_USART_CR1_CMIE) | +			   (0 << STM_USART_CR1_MME) | +			   (0 << STM_USART_CR1_M0) | +			   (0 << STM_USART_CR1_WAKE) | +			   (0 << STM_USART_CR1_PCE) | +			   (0 << STM_USART_CR1_PS) | +			   (0 << STM_USART_CR1_PEIE) | +			   (0 << STM_USART_CR1_TXEIE) | +			   (0 << STM_USART_CR1_TCIE) | +			   (1 << STM_USART_CR1_RXNEIE) | +			   (0 << STM_USART_CR1_IDLEIE) | +			   (1 << STM_USART_CR1_TE) | +			   (1 << STM_USART_CR1_RE) | +			   (0 << STM_USART_CR1_UESM) | +			   (0 << STM_USART_CR1_UE)); + +	usart->reg->cr2 = ((0 << STM_USART_CR2_ADD) | +			   (0 << STM_USART_CR2_RTOEN) | +			   (0 << STM_USART_CR2_ABRMOD) | +			   (0 << STM_USART_CR2_ABREN) | +			   (0 << STM_USART_CR2_MSBFIRST) | +			   (0 << STM_USART_CR2_DATAINV) | +			   (0 << STM_USART_CR2_TXINV) | +			   (0 << STM_USART_CR2_RXINV) | +			   (0 << STM_USART_CR2_SWAP) | +			   (0 << STM_USART_CR2_LINEN) | +			   (0 << STM_USART_CR2_STOP) | +			   (0 << STM_USART_CR2_CLKEN) | +			   (0 << STM_USART_CR2_CPOL) | +			   (0 << STM_USART_CR2_CHPA) | +			   (0 << STM_USART_CR2_LBCL) | +			   (0 << STM_USART_CR2_LBDIE) | +			   (0 << STM_USART_CR2_LBDL) | +			   (0 << STM_USART_CR2_ADDM7)); + +	usart->reg->cr3 = ((0 << STM_USART_CR3_WUFIE) | +			   (0 << STM_USART_CR3_WUS) | +			   (0 << STM_USART_CR3_SCARCNT) | +			   (0 << STM_USART_CR3_DEP) | +			   (0 << STM_USART_CR3_DEM) | +			   (0 << STM_USART_CR3_DDRE) | +			   (0 << STM_USART_CR3_OVRDIS) | +			   (0 << STM_USART_CR3_ONEBIT) | +			   (0 << STM_USART_CR3_CTIIE) | +			   (0 << STM_USART_CR3_CTSE) | +			   (0 << STM_USART_CR3_RTSE) | +			   (0 << STM_USART_CR3_DMAT) | +			   (0 << STM_USART_CR3_DMAR) | +			   (0 << STM_USART_CR3_SCEN) | +			   (0 << STM_USART_CR3_NACK) | +			   (0 << STM_USART_CR3_HDSEL) | +			   (0 << STM_USART_CR3_IRLP) | +			   (0 << STM_USART_CR3_IREN) | +			   (0 << STM_USART_CR3_EIE)); + + +	/* Pick a 9600 baud rate */ +	ao_usart_set_speed(usart, AO_SERIAL_SPEED_9600); + +	/* Enable the usart */ +	usart->reg->cr1 |= (1 << STM_USART_CR1_UE); + +} + +#if HAS_SERIAL_HW_FLOW +static void +ao_usart_set_flow(struct ao_stm_usart *usart) +{ +	usart->reg->cr3 |= ((1 << STM_USART_CR3_CTSE) | +			    (1 << STM_USART_CR3_RTSE)); +} +#endif + +#if HAS_SERIAL_1 + +struct ao_stm_usart ao_stm_usart1; + +void stm_usart1_isr(void) { ao_usart_isr(&ao_stm_usart1, USE_SERIAL_1_STDIN); } + +char +ao_serial1_getchar(void) +{ +	return ao_usart_getchar(&ao_stm_usart1); +} + +void +ao_serial1_putchar(char c) +{ +	ao_usart_putchar(&ao_stm_usart1, c); +} + +int +_ao_serial1_pollchar(void) +{ +	return _ao_usart_pollchar(&ao_stm_usart1); +} + +uint8_t +_ao_serial1_sleep_for(uint16_t timeout) +{ +	return _ao_usart_sleep_for(&ao_stm_usart1, timeout); +} + +void +ao_serial1_drain(void) +{ +	ao_usart_drain(&ao_stm_usart1); +} + +void +ao_serial1_set_speed(uint8_t speed) +{ +	ao_usart_drain(&ao_stm_usart1); +	ao_usart_set_speed(&ao_stm_usart1, speed); +} +#endif	/* HAS_SERIAL_1 */ + +#if HAS_SERIAL_2 + +struct ao_stm_usart ao_stm_usart2; + +void stm_usart2_isr(void) { ao_usart_isr(&ao_stm_usart2, USE_SERIAL_2_STDIN); } + +char +ao_serial2_getchar(void) +{ +	return ao_usart_getchar(&ao_stm_usart2); +} + +void +ao_serial2_putchar(char c) +{ +	ao_usart_putchar(&ao_stm_usart2, c); +} + +int +_ao_serial2_pollchar(void) +{ +	return _ao_usart_pollchar(&ao_stm_usart2); +} + +uint8_t +_ao_serial2_sleep_for(uint16_t timeout) +{ +	return _ao_usart_sleep_for(&ao_stm_usart2, timeout); +} + +void +ao_serial2_drain(void) +{ +	ao_usart_drain(&ao_stm_usart2); +} + +void +ao_serial2_set_speed(uint8_t speed) +{ +	ao_usart_drain(&ao_stm_usart2); +	ao_usart_set_speed(&ao_stm_usart2, speed); +} + +#if HAS_SERIAL_SW_FLOW +void +ao_serial2_cts(void) +{ +	_ao_usart_cts(&ao_stm_usart2); +} +#endif + +#endif	/* HAS_SERIAL_2 */ + +#if HAS_SERIAL_SW_FLOW +static void +ao_serial_set_sw_rts_cts(struct ao_stm_usart *usart, +			 void (*isr)(void), +			 struct stm_gpio *port_rts, +			 int pin_rts, +			 struct stm_gpio *port_cts, +			 int pin_cts) +{ +	/* Pull RTS low to note that there's space in the FIFO +	 */ +	ao_enable_output(port_rts, pin_rts, foo, 0); +	usart->gpio_rts = port_rts; +	usart->pin_rts = pin_rts; +	usart->rts = 1; + +	ao_exti_setup(port_cts, pin_cts, AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED, isr); +	usart->gpio_cts = port_cts; +	usart->pin_cts = pin_cts; +} +#endif + +void +ao_serial_init(void) +{ +#if HAS_SERIAL_1 +	/* +	 *	TX	RX +	 *	PA9	PA10 +	 *	PB6	PB7 +	 */ + +#if SERIAL_1_PA9_PA10 +	stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN); + +	stm_afr_set(&stm_gpioa, 9, STM_AFR_AF1); +	stm_afr_set(&stm_gpioa, 10, STM_AFR_AF1); +#else +#if SERIAL_1_PB6_PB7 +	stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN); + +	stm_afr_set(&stm_gpiob, 6, STM_AFR_AF0); +	stm_afr_set(&stm_gpiob, 7, STM_AFR_AF0); +#else +#error "No SERIAL_1 port configuration specified" +#endif +#endif +	/* Enable USART */ +	stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_USART1EN); + +	ao_stm_usart1.reg = &stm_usart1; +	ao_usart_init(&ao_stm_usart1); + +	stm_nvic_set_enable(STM_ISR_USART1_POS); +	stm_nvic_set_priority(STM_ISR_USART1_POS, 4); +#if USE_SERIAL_1_STDIN && !DELAY_SERIAL_1_STDIN +	ao_add_stdio(_ao_serial1_pollchar, +		     ao_serial1_putchar, +		     NULL); +#endif +#endif + +#if HAS_SERIAL_2 +	/* +	 *	TX	RX +	 *	PA2	PA3 +	 *	PA14	PA15 +	 */ + +# if SERIAL_2_PA2_PA3 +	stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN); + +	stm_afr_set(&stm_gpioa, 2, STM_AFR_AF1); +	stm_afr_set(&stm_gpioa, 3, STM_AFR_AF1); +#  if USE_SERIAL_2_FLOW +#   if USE_SERIAL_2_SW_FLOW +	ao_serial_set_sw_rts_cts(&ao_stm_usart2, +				 ao_serial2_cts, +				 SERIAL_2_PORT_RTS, +				 SERIAL_2_PIN_RTS, +				 SERIAL_2_PORT_CTS, +				 SERIAL_2_PIN_CTS); +#   else +	stm_afr_set(&stm_gpioa, 0, STM_AFR_AF1); +	stm_afr_set(&stm_gpioa, 1, STM_AFR_AF1); +#   endif +#  endif +# else +#  if SERIAL_2_PA14_PA15 +	stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN); + +	stm_afr_set(&stm_gpioa, 14, STM_AFR_AF1); +	stm_afr_set(&stm_gpioa, 15, STM_AFR_AF1); +#   if USE_SERIAL_2_FLOW +#    error "Don't know how to set flowcontrol for serial 2 on PA14" +#   endif +#  else +#   if SERIAL_2_PA2_PA15 +	stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN); + +	stm_afr_set(&stm_gpioa, 2, STM_AFR_AF1); +	stm_afr_set(&stm_gpioa, 15, STM_AFR_AF1); +#    if USE_SERIAL_2_FLOW +#     error "Don't know how to set flowcontrol for serial 2 on PA2_PA15" +#    endif +#   else +#    error "No SERIAL_2 port configuration specified" +#   endif +#  endif +# endif +	/* Enable USART */ +	stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_USART2EN); + +	ao_stm_usart2.reg = &stm_usart2; +	ao_usart_init(&ao_stm_usart2); +# if USE_SERIAL_2_FLOW && !USE_SERIAL_2_SW_FLOW +	ao_usart_set_flow(&ao_stm_usart2); +# endif + +	stm_nvic_set_enable(STM_ISR_USART2_POS); +	stm_nvic_set_priority(STM_ISR_USART2_POS, 4); +# if USE_SERIAL_2_STDIN && !DELAY_SERIAL_2_STDIN +	ao_add_stdio(_ao_serial2_pollchar, +		     ao_serial2_putchar, +		     NULL); +# endif +#endif +} diff --git a/src/stmf0/ao_spi_stm.c b/src/stmf0/ao_spi_stm.c index 0448ad8c..5e76d6c3 100644 --- a/src/stmf0/ao_spi_stm.c +++ b/src/stmf0/ao_spi_stm.c @@ -536,12 +536,18 @@ void  ao_spi_init(void)  {  #if HAS_SPI_1 +#ifndef SPI_1_PA5_PA6_PA7 +#error SPI_1_PA5_PA6_PA7 undefined +#endif  # if SPI_1_PA5_PA6_PA7  	stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN);  	stm_ospeedr_set(&stm_gpioa, 5, SPI_1_OSPEEDR);  	stm_ospeedr_set(&stm_gpioa, 6, SPI_1_OSPEEDR);  	stm_ospeedr_set(&stm_gpioa, 7, SPI_1_OSPEEDR);  # endif +# ifndef SPI_1_PB3_PB4_PB5 +# error SPI_1_PB3_PB4_PB5 undefined +# endif  # if SPI_1_PB3_PB4_PB5  	stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN);  	stm_ospeedr_set(&stm_gpiob, 3, SPI_1_OSPEEDR); diff --git a/src/stmf0/ao_spi_stm_slave.c b/src/stmf0/ao_spi_stm_slave.c new file mode 100644 index 00000000..962ff2c6 --- /dev/null +++ b/src/stmf0/ao_spi_stm_slave.c @@ -0,0 +1,339 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <ao.h> + +struct ao_spi_stm_slave_info { +	uint8_t	miso_dma_index; +	uint8_t mosi_dma_index; +	struct stm_spi *stm_spi; +}; + +static uint8_t		ao_spi_slave_mutex[STM_NUM_SPI]; +static uint8_t		ao_spi_slave_index[STM_NUM_SPI]; + +static const struct ao_spi_stm_slave_info ao_spi_stm_slave_info[STM_NUM_SPI] = { +	{ +		.miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_RX), +		.mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_TX), +		&stm_spi1 +	}, +	{ +		.miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_RX), +		.mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_TX), +		&stm_spi2 +	} +}; + +static uint8_t	spi_dev_null; + +void +ao_spi_slave_send(void *block, uint16_t len) +{ +	struct stm_spi *stm_spi = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].stm_spi; +	uint8_t	mosi_dma_index = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].mosi_dma_index; +	uint8_t	miso_dma_index = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].miso_dma_index; + +	/* Set up the transmit DMA to deliver data */ +	ao_dma_set_transfer(mosi_dma_index, +			    &stm_spi->dr, +			    block, +			    len, +			    (0 << STM_DMA_CCR_MEM2MEM) | +			    (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) | +			    (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) | +			    (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) | +			    (1 << STM_DMA_CCR_MINC) | +			    (0 << STM_DMA_CCR_PINC) | +			    (0 << STM_DMA_CCR_CIRC) | +			    (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR)); + +	/* Clear RXNE */ +	(void) stm_spi->dr; + +	/* Set up the receive DMA -- when this is done, we know the SPI unit +	 * is idle. Without this, we'd have to poll waiting for the BSY bit to +	 * be cleared +	 */ +	ao_dma_set_transfer(miso_dma_index, +			    &stm_spi->dr, +			    &spi_dev_null, +			    len, +			    (0 << STM_DMA_CCR_MEM2MEM) | +			    (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) | +			    (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) | +			    (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) | +			    (0 << STM_DMA_CCR_MINC) | +			    (0 << STM_DMA_CCR_PINC) | +			    (0 << STM_DMA_CCR_CIRC) | +			    (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR)); +	stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) | +			(0 << STM_SPI_CR2_RXNEIE) | +			(0 << STM_SPI_CR2_ERRIE) | +			(0 << STM_SPI_CR2_SSOE) | +			(1 << STM_SPI_CR2_TXDMAEN) | +			(1 << STM_SPI_CR2_RXDMAEN)); +	ao_dma_start(miso_dma_index); +	ao_dma_start(mosi_dma_index); +	ao_arch_critical( +		while (!ao_dma_done[miso_dma_index]) +			ao_sleep(&ao_dma_done[miso_dma_index]); +		); +	ao_dma_done_transfer(mosi_dma_index); +	ao_dma_done_transfer(miso_dma_index); +} + +uint8_t +ao_spi_slave_recv(void *block, uint16_t len) +{ +	struct stm_spi *stm_spi = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].stm_spi; +	uint8_t	mosi_dma_index = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].mosi_dma_index; +	uint8_t	miso_dma_index = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].miso_dma_index; + +	/* Set up transmit DMA to make the SPI hardware actually run */ +	ao_dma_set_transfer(mosi_dma_index, +			    &stm_spi->dr, +			    &spi_dev_null, +			    len, +			    (0 << STM_DMA_CCR_MEM2MEM) | +			    (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) | +			    (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) | +			    (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) | +			    (0 << STM_DMA_CCR_MINC) | +			    (0 << STM_DMA_CCR_PINC) | +			    (0 << STM_DMA_CCR_CIRC) | +			    (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR)); + +	/* Clear RXNE */ +	(void) stm_spi->dr; + +	/* Set up the receive DMA to capture data */ +	ao_dma_set_transfer(miso_dma_index, +			    &stm_spi->dr, +			    block, +			    len, +			    (0 << STM_DMA_CCR_MEM2MEM) | +			    (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) | +			    (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) | +			    (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) | +			    (1 << STM_DMA_CCR_MINC) | +			    (0 << STM_DMA_CCR_PINC) | +			    (0 << STM_DMA_CCR_CIRC) | +			    (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR)); + +	stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) | +			(0 << STM_SPI_CR2_RXNEIE) | +			(0 << STM_SPI_CR2_ERRIE) | +			(0 << STM_SPI_CR2_SSOE) | +			(1 << STM_SPI_CR2_TXDMAEN) | +			(1 << STM_SPI_CR2_RXDMAEN)); +	ao_dma_start(miso_dma_index); +	ao_dma_start(mosi_dma_index); + +	/* Wait until the SPI unit is done */ +	ao_arch_critical( +		while (!ao_dma_done[miso_dma_index]) +			ao_sleep(&ao_dma_done[miso_dma_index]); +		); + +	ao_dma_done_transfer(mosi_dma_index); +	ao_dma_done_transfer(miso_dma_index); +	return 1; +} + +static void +ao_spi_slave_disable_index(uint8_t spi_index) +{ +	/* Disable current config +	 */ +	switch (AO_SPI_INDEX(spi_index)) { +	case STM_SPI_INDEX(1): +		switch (spi_index) { +		case AO_SPI_1_PA5_PA6_PA7: +			stm_gpio_set(&stm_gpioa, 5, 1); +			stm_moder_set(&stm_gpioa, 5, STM_MODER_OUTPUT); +			stm_moder_set(&stm_gpioa, 6, STM_MODER_INPUT); +			stm_moder_set(&stm_gpioa, 7, STM_MODER_OUTPUT); +			break; +		case AO_SPI_1_PB3_PB4_PB5: +			stm_gpio_set(&stm_gpiob, 3, 1); +			stm_moder_set(&stm_gpiob, 3, STM_MODER_OUTPUT); +			stm_moder_set(&stm_gpiob, 4, STM_MODER_INPUT); +			stm_moder_set(&stm_gpiob, 5, STM_MODER_OUTPUT); +			break; +		case AO_SPI_1_PE13_PE14_PE15: +			stm_gpio_set(&stm_gpioe, 13, 1); +			stm_moder_set(&stm_gpioe, 13, STM_MODER_OUTPUT); +			stm_moder_set(&stm_gpioe, 14, STM_MODER_INPUT); +			stm_moder_set(&stm_gpioe, 15, STM_MODER_OUTPUT); +			break; +		} +		break; +	case STM_SPI_INDEX(2): +		switch (spi_index) { +		case AO_SPI_2_PB13_PB14_PB15: +			stm_gpio_set(&stm_gpiob, 13, 1); +			stm_moder_set(&stm_gpiob, 13, STM_MODER_OUTPUT); +			stm_moder_set(&stm_gpiob, 14, STM_MODER_INPUT); +			stm_moder_set(&stm_gpiob, 15, STM_MODER_OUTPUT); +			break; +		case AO_SPI_2_PD1_PD3_PD4: +			stm_gpio_set(&stm_gpiod, 1, 1); +			stm_moder_set(&stm_gpiod, 1, STM_MODER_OUTPUT); +			stm_moder_set(&stm_gpiod, 3, STM_MODER_INPUT); +			stm_moder_set(&stm_gpiod, 4, STM_MODER_OUTPUT); +			break; +		} +		break; +	} +} + +static void +ao_spi_slave_enable_index(uint8_t spi_index) +{ +	switch (AO_SPI_INDEX(spi_index)) { +	case STM_SPI_INDEX(1): +		switch (spi_index) { +		case AO_SPI_1_PA5_PA6_PA7: +			stm_afr_set(&stm_gpioa, 5, STM_AFR_AF5); +			stm_afr_set(&stm_gpioa, 6, STM_AFR_AF5); +			stm_afr_set(&stm_gpioa, 7, STM_AFR_AF5); +			break; +		case AO_SPI_1_PB3_PB4_PB5: +			stm_afr_set(&stm_gpiob, 3, STM_AFR_AF5); +			stm_afr_set(&stm_gpiob, 4, STM_AFR_AF5); +			stm_afr_set(&stm_gpiob, 5, STM_AFR_AF5); +			break; +		case AO_SPI_1_PE13_PE14_PE15: +			stm_afr_set(&stm_gpioe, 13, STM_AFR_AF5); +			stm_afr_set(&stm_gpioe, 14, STM_AFR_AF5); +			stm_afr_set(&stm_gpioe, 15, STM_AFR_AF5); +			break; +		} +		break; +	case STM_SPI_INDEX(2): +		switch (spi_index) { +		case AO_SPI_2_PB13_PB14_PB15: +			stm_afr_set(&stm_gpiob, 13, STM_AFR_AF5); +			stm_afr_set(&stm_gpiob, 14, STM_AFR_AF5); +			stm_afr_set(&stm_gpiob, 15, STM_AFR_AF5); +			break; +		case AO_SPI_2_PD1_PD3_PD4: +			stm_afr_set(&stm_gpiod, 1, STM_AFR_AF5); +			stm_afr_set(&stm_gpiod, 3, STM_AFR_AF5); +			stm_afr_set(&stm_gpiod, 4, STM_AFR_AF5); +			break; +		} +		break; +	} +} + +void +ao_spi_slave_get(uint8_t spi_index, uint32_t speed) +{ +	uint8_t		id = AO_SPI_INDEX(spi_index); +	struct stm_spi	*stm_spi = ao_spi_stm_slave_info[id].stm_spi; + +	ao_mutex_get(&ao_spi_slave_mutex[id]); +	stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) |			/* Three wire mode */ +			(0 << STM_SPI_CR1_BIDIOE) | +			(0 << STM_SPI_CR1_CRCEN) |			/* CRC disabled */ +			(0 << STM_SPI_CR1_CRCNEXT) | +			(0 << STM_SPI_CR1_DFF) | +			(0 << STM_SPI_CR1_RXONLY) | +			(1 << STM_SPI_CR1_SSM) |        		/* Software SS handling */ +			(1 << STM_SPI_CR1_SSI) |			/*  ... */ +			(0 << STM_SPI_CR1_LSBFIRST) |			/* Big endian */ +			(1 << STM_SPI_CR1_SPE) |			/* Enable SPI unit */ +			(speed << STM_SPI_CR1_BR) |	/* baud rate to pclk/4 */ +			(1 << STM_SPI_CR1_MSTR) | +			(0 << STM_SPI_CR1_CPOL) |			/* Format 0 */ +			(0 << STM_SPI_CR1_CPHA)); +	if (spi_index != ao_spi_slave_index[id]) { +		 +		/* Disable old config +		 */ +		ao_spi_slave_disable_index(ao_spi_slave_index[id]); + +		/* Enable new config +		 */ +		ao_spi_slave_enable_index(spi_index); +		 +		/* Remember current config +		 */ +		ao_spi_slave_index[id] = spi_index; +	} +} + +void +ao_spi_slave_put(uint8_t spi_index) +{ +	uint8_t		id = AO_SPI_INDEX(spi_index); +	struct stm_spi	*stm_spi = ao_spi_stm_slave_info[id].stm_spi; + +	stm_spi->cr1 = 0; +	ao_mutex_put(&ao_spi_slave_mutex[id]); +} + +static void +ao_spi_channel_init(uint8_t spi_index) +{ +	uint8_t		id = AO_SPI_INDEX(spi_index); +	struct stm_spi	*stm_spi = ao_spi_stm_slave_info[id].stm_spi; + +	ao_spi_slave_disable_index(spi_index); + +	stm_spi->cr1 = 0; +	(void) stm_spi->sr; +	stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) | +			(0 << STM_SPI_CR2_RXNEIE) | +			(0 << STM_SPI_CR2_ERRIE) | +			(0 << STM_SPI_CR2_SSOE) | +			(0 << STM_SPI_CR2_TXDMAEN) | +			(0 << STM_SPI_CR2_RXDMAEN)); +} + +void +ao_spi_slave_init(void) +{ +#if HAS_SPI_SLAVE_1 +# if SPI_1_PA5_PA6_PA7 +	stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN); +# endif +# if SPI_1_PB3_PB4_PB5 +	stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN); +# endif +# if SPI_1_PE13_PE14_PE15 +	stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOEEN); +# endif +	stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN); +	ao_spi_slave_index[0] = AO_SPI_CONFIG_NONE; +	ao_spi_channel_init(0); +#endif + +#if HAS_SPI_SLAVE_2 +# if SPI_2_PB13_PB14_PB15 +	stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN); +# endif +# if SPI_2_PD1_PD3_PD4 +	stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN); +# endif +	stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN); +	ao_spi_slave_index[1] = AO_SPI_CONFIG_NONE; +	ao_spi_channel_init(1); +#endif +} diff --git a/src/stmf0/stm32f0.h b/src/stmf0/stm32f0.h index bafa763a..e53a5dfd 100644 --- a/src/stmf0/stm32f0.h +++ b/src/stmf0/stm32f0.h @@ -1812,15 +1812,15 @@ extern struct stm_tim23 stm_tim2, stm_tim3;  #define STM_TIM23_CCMR2_OC4CE	15  #define STM_TIM23_CCMR2_OC4M	12 -#define  STM_TIM23_CCMR2_OCM_FROZEN			0 -#define  STM_TIM23_CCMR2_OCM_SET_HIGH_ON_MATCH	1 -#define  STM_TIM23_CCMR2_OCM_SET_LOW_ON_MATCH		2 -#define  STM_TIM23_CCMR2_OCM_TOGGLE			3 -#define  STM_TIM23_CCMR2_OCM_FORCE_LOW			4 -#define  STM_TIM23_CCMR2_OCM_FORCE_HIGH			5 -#define  STM_TIM23_CCMR2_OCM_PWM_MODE_1			6 -#define  STM_TIM23_CCMR2_OCM_PWM_MODE_2			7 -#define  STM_TIM23_CCMR2_OCM_MASK			7 +#define  STM_TIM23_CCMR2_OC4M_FROZEN			0 +#define  STM_TIM23_CCMR2_OC4M_SET_HIGH_ON_MATCH	1 +#define  STM_TIM23_CCMR2_OC4M_SET_LOW_ON_MATCH		2 +#define  STM_TIM23_CCMR2_OC4M_TOGGLE			3 +#define  STM_TIM23_CCMR2_OC4M_FORCE_LOW			4 +#define  STM_TIM23_CCMR2_OC4M_FORCE_HIGH		5 +#define  STM_TIM23_CCMR2_OC4M_PWM_MODE_1		6 +#define  STM_TIM23_CCMR2_OC4M_PWM_MODE_2		7 +#define  STM_TIM23_CCMR2_OC4M_MASK			7  #define STM_TIM23_CCMR2_OC4PE	11  #define STM_TIM23_CCMR2_OC4FE	10  #define STM_TIM23_CCMR2_CC4S	8 @@ -1832,15 +1832,15 @@ extern struct stm_tim23 stm_tim2, stm_tim3;  #define STM_TIM23_CCMR2_OC3CE	7  #define STM_TIM23_CCMR2_OC3M	4 -#define  STM_TIM23_CCMR2_OCM_FROZEN			0 -#define  STM_TIM23_CCMR2_OCM_SET_HIGH_ON_MATCH		1 -#define  STM_TIM23_CCMR2_OCM_SET_LOW_ON_MATCH		2 -#define  STM_TIM23_CCMR2_OCM_TOGGLE			3 -#define  STM_TIM23_CCMR2_OCM_FORCE_LOW			4 -#define  STM_TIM23_CCMR2_OCM_FORCE_HIGH			5 +#define  STM_TIM23_CCMR2_OC3M_FROZEN			0 +#define  STM_TIM23_CCMR2_OC3M_SET_HIGH_ON_MATCH		1 +#define  STM_TIM23_CCMR2_OC3M_SET_LOW_ON_MATCH		2 +#define  STM_TIM23_CCMR2_OC3M_TOGGLE			3 +#define  STM_TIM23_CCMR2_OC3M_FORCE_LOW			4 +#define  STM_TIM23_CCMR2_OC3M_FORCE_HIGH		5  #define  STM_TIM23_CCMR2_OC3M_PWM_MODE_1		6 -#define  STM_TIM23_CCMR2_OCM_PWM_MODE_2			7 -#define  STM_TIM23_CCMR2_OCM_MASK			7 +#define  STM_TIM23_CCMR2_OC3M_PWM_MODE_2		7 +#define  STM_TIM23_CCMR2_OC3M_MASK			7  #define STM_TIM23_CCMR2_OC3PE	11  #define STM_TIM23_CCMR2_OC3FE	2  #define STM_TIM23_CCMR2_CC3S	0 @@ -2010,4 +2010,129 @@ struct stm_exti {  extern struct stm_exti stm_exti; +struct stm_usart { +	vuint32_t	cr1;	/* control register 1 */ +	vuint32_t	cr2;	/* control register 2 */ +	vuint32_t	cr3;	/* control register 3 */ +	vuint32_t	brr;	/* baud rate register */ + +	vuint32_t	gtpr;	/* guard time and prescaler */ +	vuint32_t	rtor;	/* receiver timeout register */ +	vuint32_t	rqr;	/* request register */ +	vuint32_t	isr;	/* interrupt and status register */ + +	vuint32_t	icr;	/* interrupt flag clear register */ +	vuint32_t	rdr;	/* receive data register */ +	vuint32_t	tdr;	/* transmit data register */ +}; + +#define STM_USART_CR1_M1	28 +#define STM_USART_CR1_EOBIE	27 +#define STM_USART_CR1_RTOIE	26 +#define STM_USART_CR1_DEAT	21 +#define STM_USART_CR1_DEDT	16 +#define STM_USART_CR1_OVER8	15 +#define STM_USART_CR1_CMIE	14 +#define STM_USART_CR1_MME	13 +#define STM_USART_CR1_M0	12 +#define STM_USART_CR1_WAKE	11 +#define STM_USART_CR1_PCE	10 +#define STM_USART_CR1_PS	9 +#define STM_USART_CR1_PEIE	8 +#define STM_USART_CR1_TXEIE	7 +#define STM_USART_CR1_TCIE	6 +#define STM_USART_CR1_RXNEIE	5 +#define STM_USART_CR1_IDLEIE	4 +#define STM_USART_CR1_TE	3 +#define STM_USART_CR1_RE	2 +#define STM_USART_CR1_UESM	1 +#define STM_USART_CR1_UE	0 + +#define STM_USART_CR2_ADD	24 +#define STM_USART_CR2_RTOEN	23 +#define STM_USART_CR2_ABRMOD	21 +#define STM_USART_CR2_ABREN	20 +#define STM_USART_CR2_MSBFIRST	19 +#define STM_USART_CR2_DATAINV	18 +#define STM_USART_CR2_TXINV	17 +#define STM_USART_CR2_RXINV	16 +#define STM_USART_CR2_SWAP	15 +#define STM_USART_CR2_LINEN	14 +#define STM_USART_CR2_STOP	12 +#define STM_USART_CR2_CLKEN	11 +#define STM_USART_CR2_CPOL	10 +#define STM_USART_CR2_CHPA	9 +#define STM_USART_CR2_LBCL	8 +#define STM_USART_CR2_LBDIE	6 +#define STM_USART_CR2_LBDL	5 +#define STM_USART_CR2_ADDM7	4 + +#define STM_USART_CR3_WUFIE	22 +#define STM_USART_CR3_WUS	20 +#define STM_USART_CR3_SCARCNT	17 +#define STM_USART_CR3_DEP	15 +#define STM_USART_CR3_DEM	14 +#define STM_USART_CR3_DDRE	13 +#define STM_USART_CR3_OVRDIS	12 +#define STM_USART_CR3_ONEBIT	11 +#define STM_USART_CR3_CTIIE	10 +#define STM_USART_CR3_CTSE	9 +#define STM_USART_CR3_RTSE	8 +#define STM_USART_CR3_DMAT	7 +#define STM_USART_CR3_DMAR	6 +#define STM_USART_CR3_SCEN	5 +#define STM_USART_CR3_NACK	4 +#define STM_USART_CR3_HDSEL	3 +#define STM_USART_CR3_IRLP	2 +#define STM_USART_CR3_IREN	1 +#define STM_USART_CR3_EIE	0 + +#define STM_USART_GTPR_GT	8 +#define STM_USART_GTPR_PSC	0 + +#define STM_USART_RQR_TXFRQ	4 +#define STM_USART_RQR_RXFRQ	3 +#define STM_USART_RQR_MMRQ	2 +#define STM_USART_RQR_SBKRQ	1 +#define STM_USART_RQR_ABRRQ	0 + +#define STM_USART_ISR_REACK	22 +#define STM_USART_ISR_TEACK	21 +#define STM_USART_ISR_WUF	20 +#define STM_USART_ISR_RWU	19 +#define STM_USART_ISR_SBKF	18 +#define STM_USART_ISR_CMF	17 +#define STM_USART_ISR_BUSY	16 +#define STM_USART_ISR_ABRF	15 +#define STM_USART_ISR_ABRE	14 +#define STM_USART_ISR_EOBF	12 +#define STM_USART_ISR_RTOF	11 +#define STM_USART_ISR_CTS	10 +#define STM_USART_ISR_CTSIF	9 +#define STM_USART_ISR_LBDF	8 +#define STM_USART_ISR_TXE	7 +#define STM_USART_ISR_TC	6 +#define STM_USART_ISR_RXNE	5 +#define STM_USART_ISR_IDLE	4 +#define STM_USART_ISR_ORE	3 +#define STM_USART_ISR_NF	2 +#define STM_USART_ISR_FE	1 +#define STM_USART_ISR_PE	0 + +#define STM_USART_ICR_WUCF	20 +#define STM_USART_ICR_CMCF	17 +#define STM_USART_ICR_EOBCF	12 +#define STM_USART_ICR_RTOCF	11 +#define STM_USART_ICR_CTSCF	9 +#define STM_USART_ICR_LBDCF	8 +#define STM_USART_ICR_TCCF	6 +#define STM_USART_ICR_IDLECF	4 +#define STM_USART_ICR_ORECF	3 +#define STM_USART_ICR_NCF	2 +#define STM_USART_ICR_FECF	1 +#define STM_USART_ICR_PECF	0 + +extern struct stm_usart	stm_usart1; +extern struct stm_usart stm_usart2; +  #endif /* _STM32F0_H_ */ diff --git a/src/telebt-v3.0/Makefile b/src/telebt-v3.0/Makefile index a7ef4d64..40d1f6e4 100644 --- a/src/telebt-v3.0/Makefile +++ b/src/telebt-v3.0/Makefile @@ -58,7 +58,12 @@ ALTOS_SRC = \  	ao_monitor.c \  	$(PROFILE) \  	$(SAMPLE_PROFILE) \ -	$(STACK_GUARD) +	$(STACK_GUARD) \ +	ao_lco_func.c \ +	ao_radio_cmac.c \ +	ao_aes.c \ +	ao_aes_tables.c \ +	ao_lco_cmd.c  PRODUCT=TeleBT-v3.0  PRODUCT_DEF=-DTELEBT_V_3_0 diff --git a/src/telebt-v3.0/ao_pins.h b/src/telebt-v3.0/ao_pins.h index 61cbe9bb..62dddf2a 100644 --- a/src/telebt-v3.0/ao_pins.h +++ b/src/telebt-v3.0/ao_pins.h @@ -80,6 +80,7 @@  #define HAS_TELEMETRY		0  #define HAS_APRS		0  #define HAS_ACCEL		0 +#define HAS_AES			1  #define HAS_SPI_1		1  #define SPI_1_PA5_PA6_PA7	1	/* CC1200 */ @@ -197,6 +198,7 @@ struct ao_adc {  #define AO_CC1200_SPI_CS_PIN	10  #define AO_CC1200_SPI_BUS	AO_SPI_1_PA5_PA6_PA7  #define AO_CC1200_SPI		stm_spi1 +#define AO_CC1200_SPI_SPEED	AO_SPI_SPEED_FAST  #define AO_CC1200_INT_PORT		(&stm_gpiob)  #define AO_CC1200_INT_PIN		(11) diff --git a/src/telebt-v3.0/ao_telebt.c b/src/telebt-v3.0/ao_telebt.c index 9117863b..8775d993 100644 --- a/src/telebt-v3.0/ao_telebt.c +++ b/src/telebt-v3.0/ao_telebt.c @@ -22,6 +22,7 @@  #include <ao_eeprom.h>  #include <ao_profile.h>  #include <ao_btm.h> +#include <ao_lco_cmd.h>  #if HAS_SAMPLE_PROFILE  #include <ao_sample_profile.h>  #endif @@ -44,6 +45,8 @@ main(void)  	ao_btm_init();  	ao_cmd_init(); +	ao_lco_cmd_init(); +  	ao_eeprom_init();  	ao_usb_init(); diff --git a/src/teledongle-v3.0/ao_pins.h b/src/teledongle-v3.0/ao_pins.h index effc2322..be710aef 100644 --- a/src/teledongle-v3.0/ao_pins.h +++ b/src/teledongle-v3.0/ao_pins.h @@ -96,6 +96,7 @@  #define AO_CC1200_SPI_CS_PIN	3  #define AO_CC1200_SPI_BUS	0  #define AO_CC1200_SPI		0 +#define AO_CC1200_SPI_SPEED	AO_SPI_SPEED_8MHz  #define AO_CC1200_INT_PORT	0  #define AO_CC1200_INT_PIN	2 diff --git a/src/telefiretwo-v0.1/ao_pins.h b/src/telefiretwo-v0.1/ao_pins.h index f56061b2..1e5c0d09 100644 --- a/src/telefiretwo-v0.1/ao_pins.h +++ b/src/telefiretwo-v0.1/ao_pins.h @@ -110,6 +110,7 @@  #define AO_CC1200_SPI_CS_PIN	7  #define AO_CC1200_SPI_BUS	AO_SPI_2_PB13_PB14_PB15  #define AO_CC1200_SPI		stm_spi2 +#define AO_CC1200_SPI_SPEED	AO_SPI_SPEED_FAST  #define AO_CC1200_INT_PORT		(&stm_gpiob)  #define AO_CC1200_INT_PIN		(11) diff --git a/src/telefiretwo-v0.2/ao_pins.h b/src/telefiretwo-v0.2/ao_pins.h index 70af5dd1..469e9937 100644 --- a/src/telefiretwo-v0.2/ao_pins.h +++ b/src/telefiretwo-v0.2/ao_pins.h @@ -110,6 +110,7 @@  #define AO_CC1200_SPI_CS_PIN	7  #define AO_CC1200_SPI_BUS	AO_SPI_2_PB13_PB14_PB15  #define AO_CC1200_SPI		stm_spi2 +#define AO_CC1200_SPI_SPEED	AO_SPI_SPEED_FAST  #define AO_CC1200_INT_PORT		(&stm_gpiob)  #define AO_CC1200_INT_PIN		(11) diff --git a/src/telefiretwo-v1.0/Makefile b/src/telefiretwo-v1.0/Makefile new file mode 100644 index 00000000..87d5d477 --- /dev/null +++ b/src/telefiretwo-v1.0/Makefile @@ -0,0 +1,95 @@ +# +# TeleFire build file +# + +include ../stm/Makefile.defs + +INC = \ +	ao.h \ +	ao_pins.h \ +	ao_log.h \ +	ao_arch.h \ +	ao_arch_funcs.h \ +	ao_pad.h \ +	ao_product.h \ +	ao_radio_spi.h \ +	ao_radio_cmac.h \ +	ao_cc1200_CC1200.h \ +	ao_cc1200.h \ +	stm32l.h +# +# Common AltOS sources +# + +#PROFILE=ao_profile.c +#PROFILE_DEF=-DAO_PROFILE=1 + +ALTOS_SRC = \ +	ao_boot_chain.c \ +	ao_interrupt.c \ +	ao_product.c \ +	ao_romconfig.c \ +	ao_cmd.c \ +	ao_adc_stm.c \ +	ao_data.c \ +	ao_config.c \ +	ao_task.c \ +	ao_led.c \ +	ao_stdio.c \ +	ao_panic.c \ +	ao_timer.c \ +	ao_mutex.c \ +	ao_freq.c \ +	ao_dma_stm.c \ +	ao_spi_stm.c \ +	ao_beep_stm.c \ +	ao_eeprom_stm.c \ +	ao_storage.c \ +	ao_m25.c \ +	ao_usb_stm.c \ +	ao_exti_stm.c \ +	ao_cc1200.c \ +	ao_radio_cmac.c \ +	ao_aes.c \ +	ao_aes_tables.c \ +	ao_pad.c \ +	ao_radio_cmac_cmd.c \ +	ao_log.c \ +	ao_log_firetwo.c + +PRODUCT_SRC = \ +	ao_telefiretwo.c + +PRODUCT=TeleFireTwo-v1.0 +PRODUCT_DEF=-DTELEFIRETWO_V_1_0 +IDPRODUCT=0x000f + +CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) -Os -g + +PROGNAME = telefiretwo-v1.0 +PROG = $(PROGNAME)-$(VERSION).elf +HEX = $(PROGNAME)-$(VERSION).ihx + +SRC = $(ALTOS_SRC) $(PRODUCT_SRC) +OBJ=$(SRC:.c=.o) + +all: $(PROG) $(HEX) + +$(PROG): Makefile $(OBJ) altos.ld +	$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) + +$(OBJ): $(INC) + +ao_product.h: ao-make-product.5c ../Version +	$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean:	clean + +clean: +	rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx +	rm -f ao_product.h + +install: + +uninstall: + diff --git a/src/telefiretwo-v1.0/ao_pins.h b/src/telefiretwo-v1.0/ao_pins.h new file mode 100644 index 00000000..b2f5a5ab --- /dev/null +++ b/src/telefiretwo-v1.0/ao_pins.h @@ -0,0 +1,233 @@ +/* + * Copyright © 2010 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#define HAS_RADIO		1 +#define HAS_RADIO_RATE		1 +#define HAS_TELEMETRY		0 + +#define HAS_FLIGHT		0 +#define HAS_USB			1 +#define HAS_BEEP		1 +#define BEEPER_CHANNEL		4 +#define HAS_GPS			0 +#define HAS_SERIAL_1		0 +#define HAS_ADC			1 +#define HAS_DBG			0 +#define HAS_EEPROM		1 +#define HAS_LOG			1 +#define HAS_PAD			1 +#define USE_INTERNAL_FLASH	0 +#define IGNITE_ON_P0		0 +#define PACKET_HAS_MASTER	0 +#define PACKET_HAS_SLAVE	0 +#define AO_DATA_RING		32 +#define HAS_FIXED_PAD_BOX	1 + +#define LOG_ERASE_MARK		0x55 + +/* 8MHz High speed external crystal */ +#define AO_HSE			8000000 + +/* PLLVCO = 96MHz (so that USB will work) */ +#define AO_PLLMUL		12 +#define AO_RCC_CFGR_PLLMUL	(STM_RCC_CFGR_PLLMUL_12) + +#define AO_CC1200_FOSC		40000000 + +/* SYSCLK = 32MHz (no need to go faster than CPU) */ +#define AO_PLLDIV		3 +#define AO_RCC_CFGR_PLLDIV	(STM_RCC_CFGR_PLLDIV_3) + +/* HCLK = 32MHz (CPU clock) */ +#define AO_AHB_PRESCALER	1 +#define AO_RCC_CFGR_HPRE_DIV	STM_RCC_CFGR_HPRE_DIV_1 + +/* Run APB1 at 16MHz (HCLK/2) */ +#define AO_APB1_PRESCALER	2 +#define AO_RCC_CFGR_PPRE1_DIV	STM_RCC_CFGR_PPRE2_DIV_2 + +/* Run APB2 at 16MHz (HCLK/2) */ +#define AO_APB2_PRESCALER	2 +#define AO_RCC_CFGR_PPRE2_DIV	STM_RCC_CFGR_PPRE2_DIV_2 + +#define HAS_EEPROM		1 +#define USE_EEPROM_CONFIG	1 +#define USE_STORAGE_CONFIG	0 +#define HAS_USB			1 +#define HAS_RADIO		1 +#define HAS_RADIO_RATE		1 +#define HAS_TELEMETRY		0 +#define HAS_AES			1 + +#define HAS_SPI_1		0 +#define SPI_1_PA5_PA6_PA7	0 +#define SPI_1_PB3_PB4_PB5	0 +#define SPI_1_PE13_PE14_PE15	0 + +#define HAS_SPI_2		1	/* CC1200 */ +#define SPI_2_PB13_PB14_PB15	1 +#define SPI_2_PD1_PD3_PD4	0 +#define SPI_2_GPIO		(&stm_gpiob) +#define SPI_2_SCK		13 +#define SPI_2_MISO		14 +#define SPI_2_MOSI		15 +#define SPI_2_OSPEEDR		STM_OSPEEDR_10MHz + +#define HAS_I2C_1		0 + +#define HAS_I2C_2		0 + +#define PACKET_HAS_SLAVE	0 +#define PACKET_HAS_MASTER	0 + +#define FAST_TIMER_FREQ		10000	/* .1ms for debouncing */ + +/* + * SPI Flash memory + */ + +#define M25_MAX_CHIPS           1 +#define AO_M25_SPI_CS_PORT      (&stm_gpioa) +#define AO_M25_SPI_CS_MASK      (1 << 15) +#define AO_M25_SPI_BUS          AO_SPI_2_PB13_PB14_PB15 + +/* + * Radio is a cc1200 connected via SPI + */ + +#define AO_RADIO_CAL_DEFAULT 	5695733 + +#define AO_FEC_DEBUG		0 +#define AO_CC1200_SPI_CS_PORT	(&stm_gpioa) +#define AO_CC1200_SPI_CS_PIN	7 +#define AO_CC1200_SPI_BUS	AO_SPI_2_PB13_PB14_PB15 +#define AO_CC1200_SPI		stm_spi2 +#define AO_CC1200_SPI_SPEED	AO_SPI_SPEED_FAST + +#define AO_CC1200_INT_PORT		(&stm_gpiob) +#define AO_CC1200_INT_PIN		(11) + +#define AO_CC1200_INT_GPIO	2 +#define AO_CC1200_INT_GPIO_IOCFG	CC1200_IOCFG2 + +#define LED_PORT_0		(&stm_gpioa) +#define LED_PORT_1		(&stm_gpiob) + +#define LED_PORT_0_ENABLE	STM_RCC_AHBENR_GPIOAEN +#define LED_PORT_1_ENABLE	STM_RCC_AHBENR_GPIOBEN + +/* Port A, pins 4-6 */ +#define LED_PORT_0_SHIFT	4 +#define LED_PORT_0_MASK		0x7 +#define LED_PIN_GREEN		0 +#define LED_PIN_AMBER		1 +#define LED_PIN_RED		2 +#define AO_LED_RED		(1 << LED_PIN_RED) +#define AO_LED_AMBER		(1 << LED_PIN_AMBER) +#define AO_LED_GREEN		(1 << LED_PIN_GREEN) + +/* Port B, pins 4-5 */ +#define LED_PORT_1_SHIFT	0 +#define LED_PORT_1_MASK		(0x3 << 4) +#define LED_PIN_CONT_0		4 +#define LED_PIN_ARMED		5 + +#define AO_LED_ARMED		(1 << LED_PIN_ARMED) +#define AO_LED_CONTINUITY(c)	(1 << (4 - (c))) +#define AO_LED_CONTINUITY_MASK	(0x1 << 4) + +#define LEDS_AVAILABLE		(LED_PORT_0_MASK|LED_PORT_1_MASK) + +/* Alarm A */ +#define AO_SIREN +#define AO_SIREN_PORT		(&stm_gpiob) +#define AO_SIREN_PIN		8 + +/* Alarm B */ +#define AO_STROBE +#define AO_STROBE_PORT		(&stm_gpiob) +#define AO_STROBE_PIN		9 + +#define SPI_CONST	0x00 + +#define AO_PAD_NUM		1 +#define	AO_PAD_PORT		(&stm_gpioa) + +#define AO_PAD_PIN_0		1 +#define AO_PAD_ADC_0		0 + +#define AO_PAD_ALL_PINS		((1 << AO_PAD_PIN_0)) +#define AO_PAD_ALL_CHANNELS	((1 << 0)) + +/* test these values with real igniters */ +#define AO_PAD_RELAY_CLOSED	3524 +#define AO_PAD_NO_IGNITER	16904 +#define AO_PAD_GOOD_IGNITER	22514 + +#define AO_PAD_ADC_PYRO		2 +#define AO_PAD_ADC_BATT		8 + +#define AO_PAD_ADC_THRUST	3 +#define AO_PAD_ADC_PRESSURE	18 + +#define AO_ADC_FIRST_PIN	0 + +#define AO_NUM_ADC		5 + +#define AO_ADC_SQ1		AO_PAD_ADC_0 +#define AO_ADC_SQ2		AO_PAD_ADC_PYRO +#define AO_ADC_SQ3		AO_PAD_ADC_BATT +#define AO_ADC_SQ4		AO_PAD_ADC_THRUST +#define AO_ADC_SQ5		AO_PAD_ADC_PRESSURE + +#define AO_PYRO_R_PYRO_SENSE	200 +#define AO_PYRO_R_SENSE_GND	22 + +#define AO_FIRE_R_POWER_FET	0 +#define AO_FIRE_R_FET_SENSE	200 +#define AO_FIRE_R_SENSE_GND	22 + +#define HAS_ADC_TEMP		0 + +struct ao_adc { +	int16_t		sense[AO_PAD_NUM]; +	int16_t		pyro; +	int16_t		batt; +	int16_t		thrust; +	int16_t		pressure; +}; + +#define AO_ADC_DUMP(p)							\ +	printf ("tick: %5u 0: %5d pyro: %5d batt %5d thrust %5d pressure %5d\n", \ +		(p)->tick,						\ +		(p)->adc.sense[0],					\ +		(p)->adc.pyro,						\ +		(p)->adc.batt,						\ +		(p)->adc.thrust,					\ +		(p)->adc.pressure) + +#define AO_ADC_PINS	((1 << AO_PAD_ADC_0) | \ +			 (1 << AO_PAD_ADC_PYRO) | \ +			 (1 << AO_PAD_ADC_BATT) | \ +			 (1 << AO_PAD_ADC_THRUST) | \ +			 (1 << AO_PAD_ADC_PRESSURE)) + +#endif /* _AO_PINS_H_ */ diff --git a/src/telefiretwo-v1.0/ao_telefiretwo.c b/src/telefiretwo-v1.0/ao_telefiretwo.c new file mode 100644 index 00000000..115b3e91 --- /dev/null +++ b/src/telefiretwo-v1.0/ao_telefiretwo.c @@ -0,0 +1,73 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <ao.h> +#include <ao_log.h> +#include <ao_pad.h> +#include <ao_exti.h> +#include <ao_radio_cmac_cmd.h> +#include <ao_eeprom.h> + +static void +set_logging(void) +{ +	ao_cmd_hex(); +	ao_log_running = ao_cmd_lex_i; +	ao_wakeup(&ao_log_running); +} + +__code struct ao_cmds ao_firetwo_cmds[] = { +        { set_logging,  "L <0 off, 1 on>\0Log sensors to flash" }, +        { 0,    NULL }, +}; + +void +main(void) +{ +	ao_clock_init(); + +	ao_led_init(LEDS_AVAILABLE); + +	ao_task_init(); + +	ao_timer_init(); +	ao_spi_init(); +	ao_dma_init(); +	ao_exti_init(); + +	ao_cmd_register(&ao_firetwo_cmds[0]); +	ao_cmd_init(); + +	ao_adc_init(); + +	ao_eeprom_init(); +	ao_storage_init(); +	ao_log_init(); + +	ao_radio_init(); + +	ao_usb_init(); + +	ao_config_init(); + +	ao_pad_init(); + +//	ao_radio_cmac_cmd_init(); + +	ao_start_scheduler(); +} diff --git a/src/telefiretwo-v1.0/flash-loader/.gitignore b/src/telefiretwo-v1.0/flash-loader/.gitignore new file mode 100644 index 00000000..65fe7eab --- /dev/null +++ b/src/telefiretwo-v1.0/flash-loader/.gitignore @@ -0,0 +1,2 @@ +*.elf +*.ihx diff --git a/src/telefiretwo-v1.0/flash-loader/Makefile b/src/telefiretwo-v1.0/flash-loader/Makefile new file mode 100644 index 00000000..d429dcc4 --- /dev/null +++ b/src/telefiretwo-v1.0/flash-loader/Makefile @@ -0,0 +1,8 @@ +# +# AltOS flash loader build +# +# + +TOPDIR=../.. +HARDWARE=telefiretwo-v1.0 +include $(TOPDIR)/stm/Makefile-flash.defs diff --git a/src/telefiretwo-v1.0/flash-loader/ao_pins.h b/src/telefiretwo-v1.0/flash-loader/ao_pins.h new file mode 100644 index 00000000..ded45a40 --- /dev/null +++ b/src/telefiretwo-v1.0/flash-loader/ao_pins.h @@ -0,0 +1,33 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +/* External crystal at 8MHz */ +#define AO_HSE		8000000 + +#include <ao_flash_stm_pins.h> + +#define AO_BOOT_PIN			1 +#define AO_BOOT_APPLICATION_GPIO	stm_gpiob +#define AO_BOOT_APPLICATION_PIN		6 +#define AO_BOOT_APPLICATION_VALUE	1 +#define AO_BOOT_APPLICATION_MODE	AO_EXTI_MODE_PULL_UP + +#endif /* _AO_PINS_H_ */ diff --git a/src/telegps-v0.1/ao_pins.h b/src/telegps-v0.1/ao_pins.h index 96e8cfd7..5afc9498 100644 --- a/src/telegps-v0.1/ao_pins.h +++ b/src/telegps-v0.1/ao_pins.h @@ -148,6 +148,7 @@  #define AO_CC115L_SPI_CS_PIN	12  #define AO_CC115L_SPI_BUS	AO_SPI_2_PB13_PB14_PB15  #define AO_CC115L_SPI		stm_spi2 +#define AO_CC115L_SPI_SPEED	AO_SPI_SPEED_4MHz  #define AO_CC115L_FIFO_INT_GPIO_IOCFG	CC115L_IOCFG2  #define AO_CC115L_FIFO_INT_PORT		(&stm_gpioa) @@ -183,4 +184,8 @@  #define AO_SDCARD_SPI_CS_PIN	4  #define AO_SDCARD_SPI		stm_spi1 +#define SDCARD_DEBUG		1 +#define SDCARD_WARN		1 +#define SDCARD_TRACE		1 +  #endif /* _AO_PINS_H_ */ diff --git a/src/telegps-v0.1/ao_telegps.c b/src/telegps-v0.1/ao_telegps.c index eb8ab72d..f734d90f 100644 --- a/src/telegps-v0.1/ao_telegps.c +++ b/src/telegps-v0.1/ao_telegps.c @@ -49,16 +49,16 @@ main(void)  	ao_cmd_init();  	ao_usb_init(); -	ao_radio_init(); +//	ao_radio_init();  	ao_fat_init(); -	ao_gps_init(); -	ao_gps_report_mega_init(); +//	ao_gps_init(); +//	ao_gps_report_mega_init(); -	ao_telemetry_init(); -	ao_telemetry_set_interval(AO_SEC_TO_TICKS(1)); -	ao_rdf_set(1); +//	ao_telemetry_init(); +//	ao_telemetry_set_interval(AO_SEC_TO_TICKS(1)); +//	ao_rdf_set(1);  #if HAS_SAMPLE_PROFILE  	ao_sample_profile_init(); diff --git a/src/telegps-v0.3/ao_pins.h b/src/telegps-v0.3/ao_pins.h index 9c650cc4..28ae30a4 100644 --- a/src/telegps-v0.3/ao_pins.h +++ b/src/telegps-v0.3/ao_pins.h @@ -95,6 +95,7 @@  #define AO_CC115L_SPI_CS_PORT	0  #define AO_CC115L_SPI_CS_PIN	3  #define AO_CC115L_SPI_BUS	0 +#define AO_CC115L_SPI_SPEED	AO_SPI_SPEED_6MHz  #define AO_CC115L_FIFO_INT_GPIO_IOCFG	CC115L_IOCFG2  #define AO_CC115L_FIFO_INT_PORT		0 diff --git a/src/telegps-v1.0/ao_pins.h b/src/telegps-v1.0/ao_pins.h index 19774f63..9672ab03 100644 --- a/src/telegps-v1.0/ao_pins.h +++ b/src/telegps-v1.0/ao_pins.h @@ -97,6 +97,7 @@  #define AO_CC115L_SPI_CS_PORT	0  #define AO_CC115L_SPI_CS_PIN	3  #define AO_CC115L_SPI_BUS	0 +#define AO_CC115L_SPI_SPEED	AO_SPI_SPEED_6MHz  #define AO_CC115L_FIFO_INT_GPIO_IOCFG	CC115L_IOCFG2  #define AO_CC115L_FIFO_INT_PORT		0 diff --git a/src/telegps-v2.0/Makefile b/src/telegps-v2.0/Makefile new file mode 100644 index 00000000..19d088d3 --- /dev/null +++ b/src/telegps-v2.0/Makefile @@ -0,0 +1,89 @@ +# +# AltOS build +# +# + +include ../stmf0/Makefile.defs + +INC = \ +	ao.h \ +	ao_arch.h \ +	ao_arch_funcs.h \ +	ao_pins.h \ +	ao_product.h \ +	ao_tracker.h \ +	ao_task.h \ +	ao_cc1200.h \ +	ao_fec.h \ +	stm32f0.h \ +	Makefile + + +ALTOS_SRC = \ +	ao_adc_stm.c \ +	ao_led.c \ +	ao_interrupt.c \ +	ao_boot_chain.c \ +	ao_product.c \ +	ao_romconfig.c \ +	ao_cmd.c \ +	ao_config.c \ +	ao_task.c \ +	ao_stdio.c \ +	ao_panic.c \ +	ao_timer.c \ +	ao_mutex.c \ +	ao_freq.c \ +	ao_dma_stm.c \ +	ao_spi_stm.c \ +	ao_usb_stm.c \ +	ao_exti_stm.c \ +	ao_serial_stm.c \ +	ao_gps_ublox.c \ +	ao_gps_show.c \ +	ao_cc1200.c \ +	ao_aprs.c \ +	ao_tracker.c \ +	ao_telemetry.c \ +	ao_storage.c \ +	ao_m25.c \ +	ao_log.c \ +	ao_log_gps.c \ +	ao_distance.c \ +	ao_sqrt.c \ +	ao_data.c \ +	ao_convert_volt.c \ +	$(SAMPLE_PROFILE) + +PRODUCT=TeleGPS-v2.0 +PRODUCT_DEF=-DTELEGPS +IDPRODUCT=0x0025 + +CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) $(PROFILE_DEF) -g -Os + +PROGNAME=telegps-v2.0 +PROG=$(PROGNAME)-$(VERSION).elf +HEX=$(PROGNAME)-$(VERSION).ihx + +SRC=$(ALTOS_SRC) ao_telegps.c +OBJ=$(SRC:.c=.o) + +all: $(PROG) $(HEX) + +$(PROG): Makefile $(OBJ) altos.ld +	$(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS) + +$(OBJ): $(INC) + +ao_product.h: ao-make-product.5c ../Version +	$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean:	clean + +clean: +	rm -f *.o ao_serial_stm.h $(PROGNAME)-*.elf $(PROGNAME)-*.ihx +	rm -f ao_product.h + +install: + +uninstall: diff --git a/src/telegps-v2.0/ao_pins.h b/src/telegps-v2.0/ao_pins.h new file mode 100644 index 00000000..c51f0afb --- /dev/null +++ b/src/telegps-v2.0/ao_pins.h @@ -0,0 +1,164 @@ +/* + * Copyright © 2017 Bdale Garbee <bdale@gag.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#define LED_PORT_ENABLE STM_RCC_AHBENR_IOPBEN +#define LED_PORT        (&stm_gpiob) +#define LED_PIN_RED     5 +#define AO_LED_RED      (1 << LED_PIN_RED) + +#define LEDS_AVAILABLE  (AO_LED_RED) + +#define IS_FLASH_LOADER		0 +#define HAS_BEEP 	       0 + +#define AO_HSE                  32000000 +#define AO_RCC_CFGR_PLLMUL      STM_RCC_CFGR_PLLMUL_3 +#define AO_PLLMUL               3 +#define AO_PLLDIV               1 + +/* HCLK = 48MHz */ +#define AO_AHB_PRESCALER        1 +#define AO_RCC_CFGR_HPRE_DIV    STM_RCC_CFGR_HPRE_DIV_1 + +/* APB = 48MHz */ +#define AO_APB_PRESCALER        1 +#define AO_RCC_CFGR_PPRE_DIV    STM_RCC_CFGR_PPRE_DIV_1 + +#define AO_RCC_CFGR2_PLLDIV	STM_RCC_CFGR2_PREDIV_1 + +#define HAS_USB                         1 +#define AO_USB_DIRECTIO                 0 +#define AO_PA11_PA12_RMP                1 + +#define IS_FLASH_LOADER 0 + +/* ADC */ + +#define HAS_ADC			1 +#define AO_ADC_PIN0_PORT        (&stm_gpioa) +#define AO_ADC_PIN0_PIN         0 +#define AO_ADC_PIN0_CH          0 + +#define AO_ADC_RCC_AHBENR       ((1 << STM_RCC_AHBENR_IOPAEN)) + +#define AO_NUM_ADC              1 + +#define AO_DATA_RING		4 + +/* + * Voltage divider on ADC battery sampler + */ +#define AO_BATTERY_DIV_PLUS	56	/* 5.6k */ +#define AO_BATTERY_DIV_MINUS	100	/* 10k */ + +/* + * ADC reference in decivolts + */ +#define AO_ADC_REFERENCE_DV	33 + +struct ao_adc { +        int16_t                 v_batt; +}; + +#define AO_ADC_DUMP(p) \ +        printf("tick: %5u batt: %5d\n", \ +               (p)->tick, \ +               (p)->adc.v_batt) + +/* SPI */ +#define HAS_SPI_1               1 +#define HAS_SPI_2               0 +#define SPI_1_PA5_PA6_PA7       1 +#define SPI_1_PB3_PB4_PB5       0 +#define SPI_1_OSPEEDR           STM_OSPEEDR_HIGH + +#define HAS_MS5607              0 + +/* Flash */ + +#define M25_MAX_CHIPS           1 +#define AO_M25_SPI_CS_PORT      (&stm_gpiob) +#define AO_M25_SPI_CS_MASK      (1 << 0) +#define AO_M25_SPI_BUS          AO_SPI_1_PA5_PA6_PA7 + +#define HAS_SERIAL_1		1 +#define SERIAL_1_PB6_PB7	1 +#define USE_SERIAL_1_STDIN	0 + +#define ao_gps_getchar		ao_serial1_getchar +#define ao_gps_putchar		ao_serial1_putchar +#define ao_gps_set_speed	ao_serial1_set_speed +#define ao_gps_fifo		(ao_usart_rx_fifo) + +#define HAS_EEPROM		1 +#define USE_INTERNAL_FLASH	0 +#define HAS_RADIO		1 +#define HAS_TELEMETRY		1 +#define HAS_RDF			1 +#define HAS_APRS		1 +#define HAS_RADIO_RECV		0 + +#define HAS_GPS			1 +#define HAS_FLIGHT		0 +#define HAS_LOG			1 +#define FLIGHT_LOG_APPEND	1 +#define HAS_TRACKER		1 +#define LOG_ADC			0 + +#define AO_CONFIG_DEFAULT_APRS_INTERVAL		0 +#define AO_CONFIG_DEFAULT_RADIO_POWER		0xc0 + +/* + * GPS + */ + +#define AO_SERIAL_SPEED_UBLOX	AO_SERIAL_SPEED_9600 + + +/* + * Radio (cc1120) + */ + +/* gets pretty close to 434.550 */ + +#define AO_RADIO_CAL_DEFAULT    5695733 + +#define AO_FEC_DEBUG            0 +#define AO_CC1200_SPI_CS_PORT   (&stm_gpioa) +#define AO_CC1200_SPI_CS_PIN    5 +#define AO_CC1200_SPI_BUS       AO_SPI_1_PA5_PA6_PA7 +#define AO_CC1200_SPI           stm_spi1 +#define AO_CC1200_SPI_SPEED     AO_SPI_SPEED_FAST + +#define AO_CC1200_INT_PORT              (&stm_gpioa) +#define AO_CC1200_INT_PIN               4 +#define AO_CC1200_MCU_WAKEUP_PORT       (&stm_gpioa) +#define AO_CC1200_MCU_WAKEUP_PIN        (0) + +#define AO_CC1200_INT_GPIO      2 +#define AO_CC1200_INT_GPIO_IOCFG        CC1200_IOCFG2 + +#define AO_CC1200_MARC_GPIO     3 +#define AO_CC1200_MARC_GPIO_IOCFG       CC1200_IOCFG3 + +#define HAS_BOOT_RADIO          0 + +#endif /* _AO_PINS_H_ */ diff --git a/src/telegps-v2.0/ao_telegps.c b/src/telegps-v2.0/ao_telegps.c new file mode 100644 index 00000000..7a923d11 --- /dev/null +++ b/src/telegps-v2.0/ao_telegps.c @@ -0,0 +1,68 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <ao.h> +#include <ao_log.h> +#include <ao_exti.h> +#include <ao_tracker.h> + +int +main(void) +{ +	ao_clock_init(); + +#if HAS_STACK_GUARD +	ao_mpu_init(); +#endif + +	ao_task_init(); +	ao_timer_init(); + +	ao_spi_init(); +	ao_exti_init(); + +	ao_storage_init(); + +	ao_serial_init(); + +	ao_cmd_init(); + +	ao_usb_init(); +	ao_radio_init(); + +#if HAS_ADC +	ao_adc_init(); +#endif + +	ao_gps_init(); +#if HAS_LOG +	ao_log_init(); +#endif + +	ao_tracker_init(); + +	ao_telemetry_init(); + +#if HAS_SAMPLE_PROFILE +	ao_sample_profile_init(); +#endif +	ao_config_init(); + +	ao_start_scheduler(); +	return 0; +} diff --git a/src/telegps-v2.0/flash-loader/Makefile b/src/telegps-v2.0/flash-loader/Makefile new file mode 100644 index 00000000..c0659698 --- /dev/null +++ b/src/telegps-v2.0/flash-loader/Makefile @@ -0,0 +1,8 @@ +# +# AltOS flash loader build +# +# + +TOPDIR=../.. +HARDWARE=telegps-v2.0 +include $(TOPDIR)/stmf0/Makefile-flash.defs diff --git a/src/telegps-v2.0/flash-loader/ao_pins.h b/src/telegps-v2.0/flash-loader/ao_pins.h new file mode 100644 index 00000000..a83dbaa2 --- /dev/null +++ b/src/telegps-v2.0/flash-loader/ao_pins.h @@ -0,0 +1,36 @@ +/* + * Copyright © 2017 Bdale Garbee <bdale@gag.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#include <ao_flash_stm_pins.h> + +/* Pin 5 on debug connector */ + +#define AO_BOOT_PIN		1 +#define AO_BOOT_APPLICATION_GPIO	stm_gpioa +#define AO_BOOT_APPLICATION_PIN		15 +#define AO_BOOT_APPLICATION_VALUE	1 +#define AO_BOOT_APPLICATION_MODE	AO_EXTI_MODE_PULL_UP + +#define HAS_USB			1 +#define AO_USB_DIRECTIO		0 +#define AO_PA11_PA12_RMP	1 + +#endif /* _AO_PINS_H_ */ diff --git a/src/telelco-v0.3/ao_pins.h b/src/telelco-v0.3/ao_pins.h index d874a19b..dd4aaafb 100644 --- a/src/telelco-v0.3/ao_pins.h +++ b/src/telelco-v0.3/ao_pins.h @@ -89,6 +89,7 @@  #define AO_CC1200_SPI_CS_PIN	0  #define AO_CC1200_SPI_BUS	AO_SPI_2_PD1_PD3_PD4  #define AO_CC1200_SPI		stm_spi2 +#define AO_CC1200_SPI_SPEED	AO_SPI_SPEED_FAST  #define AO_CC1200_INT_PORT		(&stm_gpioc)  #define AO_CC1200_INT_PIN		(15) diff --git a/src/telelcotwo-v0.1/ao_pins.h b/src/telelcotwo-v0.1/ao_pins.h index 714a5c3a..60e94c67 100644 --- a/src/telelcotwo-v0.1/ao_pins.h +++ b/src/telelcotwo-v0.1/ao_pins.h @@ -91,6 +91,7 @@  #define AO_CC1200_SPI_CS_PIN	7  #define AO_CC1200_SPI_BUS	AO_SPI_2_PB13_PB14_PB15  #define AO_CC1200_SPI		stm_spi2 +#define AO_CC1200_SPI_SPEED	AO_SPI_SPEED_FAST  #define AO_CC1200_INT_PORT		(&stm_gpiob)  #define AO_CC1200_INT_PIN		(11) diff --git a/src/telemega-v2.0/ao_pins.h b/src/telemega-v2.0/ao_pins.h index b1c472da..c7c8ad19 100644 --- a/src/telemega-v2.0/ao_pins.h +++ b/src/telemega-v2.0/ao_pins.h @@ -309,6 +309,7 @@ struct ao_adc {  #define AO_CC1200_SPI_CS_PIN	5  #define AO_CC1200_SPI_BUS	AO_SPI_2_PB13_PB14_PB15  #define AO_CC1200_SPI		stm_spi2 +#define AO_CC1200_SPI_SPEED	AO_SPI_SPEED_FAST  #define AO_CC1200_INT_PORT		(&stm_gpioe)  #define AO_CC1200_INT_PIN		1 diff --git a/src/telemetrum-v3.0/ao_pins.h b/src/telemetrum-v3.0/ao_pins.h index ccf2f18f..b937b422 100644 --- a/src/telemetrum-v3.0/ao_pins.h +++ b/src/telemetrum-v3.0/ao_pins.h @@ -259,6 +259,7 @@ struct ao_adc {  #define AO_CC1200_SPI_CS_PIN	2  #define AO_CC1200_SPI_BUS	AO_SPI_2_PB13_PB14_PB15  #define AO_CC1200_SPI		stm_spi2 +#define AO_CC1200_SPI_SPEED	AO_SPI_SPEED_FAST  #define AO_CC1200_INT_PORT		(&stm_gpioa)  #define AO_CC1200_INT_PIN		(3) diff --git a/src/telemini-v2.0/ao_pins.h b/src/telemini-v2.0/ao_pins.h index 4f1d36df..d2aa4c2d 100644 --- a/src/telemini-v2.0/ao_pins.h +++ b/src/telemini-v2.0/ao_pins.h @@ -115,8 +115,8 @@  #define AO_IGNITER_FIRE_TIME	AO_MS_TO_TICKS(50)  #define AO_IGNITER_CHARGE_TIME	AO_MS_TO_TICKS(2000) -#define AO_SEND_MINI -#define AO_LOG_FORMAT		AO_LOG_FORMAT_TELEMINI +#define AO_SEND_MINI		AO_TELEMETRY_MINI2 +#define AO_LOG_FORMAT		AO_LOG_FORMAT_TELEMINI2  /*   * ADC diff --git a/src/telemini-v3.0/Makefile b/src/telemini-v3.0/Makefile new file mode 100644 index 00000000..4713b3ad --- /dev/null +++ b/src/telemini-v3.0/Makefile @@ -0,0 +1,93 @@ +# +# AltOS build +# +# + +include ../stmf0/Makefile.defs + +INC = \ +	ao.h \ +	ao_arch.h \ +	ao_arch_funcs.h \ +	ao_pins.h \ +	ao_product.h \ +	ao_cc1200.h \ +	ao_cc1200_CC1200.h \ +	stm32f0.h + +# +# Common AltOS sources +# + +ALTOS_SRC = \ +	ao_interrupt.c \ +	ao_boot_chain.c \ +	ao_romconfig.c \ +	ao_product.c \ +	ao_mutex.c \ +	ao_panic.c \ +	ao_stdio.c \ +	ao_storage.c \ +	ao_report.c \ +	ao_ignite.c \ +	ao_flight.c \ +	ao_kalman.c \ +	ao_sample.c \ +	ao_data.c \ +	ao_convert_pa.c \ +	ao_convert_volt.c \ +	ao_task.c \ +	ao_log.c \ +	ao_log_mini.c \ +	ao_cmd.c \ +	ao_config.c \ +	ao_freq.c \ +	ao_dma_stm.c \ +	ao_timer.c \ +	ao_exti_stm.c \ +	ao_spi_stm.c \ +	ao_adc_stm.c \ +	ao_usb_stm.c \ +	ao_m25.c \ +	ao_ms5607.c \ +	ao_cc1200.c \ +	ao_telemetry.c \ +	ao_packet_slave.c \ +	ao_beep_stm.c \ +	ao_packet.c + +PRODUCT=TeleMini-v3.0 +PRODUCT_DEF=-DTELEMINI_V_3_0 +IDPRODUCT=0x0027 + +CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -g -Os + +PROGNAME=telemini-v3.0 +PROG=$(PROGNAME)-$(VERSION).elf +HEX=$(PROGNAME)-$(VERSION).ihx + +SRC=$(ALTOS_SRC) ao_telemini.c +OBJ=$(SRC:.c=.o) + +all: $(PROG) $(HEX) + +$(PROG): Makefile $(OBJ) +	$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) + +ao_product.h: ao-make-product.5c ../Version +	$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +$(OBJ): $(INC) + +load: $(PROG) +	lpc-load $(PROG) + +distclean:	clean + +clean: +	rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx +	rm -f ao_product.h + +install: + +uninstall: diff --git a/src/telemini-v3.0/ao_pins.h b/src/telemini-v3.0/ao_pins.h new file mode 100644 index 00000000..351d28d8 --- /dev/null +++ b/src/telemini-v3.0/ao_pins.h @@ -0,0 +1,188 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#define HAS_BEEP		1 +#define HAS_SERIAL_1		0 +#define HAS_BATTERY_REPORT	1 + +#define AO_STACK_SIZE	448 + +#define IS_FLASH_LOADER	0 + +/* 48MHz clock based on 16MHz reference */ +//#define AO_HSI48	1 +#define AO_HSE			16000000 +#define AO_RCC_CFGR_PLLMUL	STM_RCC_CFGR_PLLMUL_3 +#define AO_RCC_CFGR2_PLLDIV	STM_RCC_CFGR2_PREDIV_1 +#define AO_PLLMUL		3 +#define AO_PLLDIV		1 + +/* HCLK = 48MHz */ +#define AO_AHB_PRESCALER	1 +#define AO_RCC_CFGR_HPRE_DIV	STM_RCC_CFGR_HPRE_DIV_1 + +/* APB = 40MHz */ +#define AO_APB_PRESCALER	1 +#define AO_RCC_CFGR_PPRE_DIV	STM_RCC_CFGR_PPRE_DIV_1 + +#define HAS_USB			1 +#define AO_USB_DIRECTIO		0 +#define AO_PA11_PA12_RMP	1 +#define AO_USB_FORCE_IDLE	1 + +#define PACKET_HAS_SLAVE	1 + +#define AO_LOG_FORMAT		AO_LOG_FORMAT_TELEMINI3 +#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX	((uint32_t) 112 * (uint32_t) 1024) + +#define HAS_BOOT_RADIO		0 + +#define HAS_ACCEL		0 +#define HAS_GPS			0 +#define HAS_RADIO		1 +#define HAS_RADIO_RATE		1 +#define HAS_FLIGHT		1 +#define HAS_EEPROM		1 +#define HAS_TELEMETRY		1 +#define AO_SEND_MINI		AO_TELEMETRY_MINI3 +#define HAS_APRS		0 +#define HAS_LOG			1 +#define USE_INTERNAL_FLASH	0 +#define HAS_IGNITE		1 +#define HAS_IGNITE_REPORT	1 +#define AO_SMALL_ALTITUDE_TABLE	1 + +/* Beeper is on Tim1 CH3 */ +#define BEEPER_CHANNEL		4 +#define BEEPER_TIMER		2 +#define BEEPER_PORT		(&stm_gpioa) +#define BEEPER_PIN		3 + +/* SPI */ + +#define HAS_SPI_1		1 +#define SPI_1_PA5_PA6_PA7	1 +#define SPI_1_PB3_PB4_PB5	1 +#define SPI_1_OSPEEDR		STM_OSPEEDR_MEDIUM + +/* M25 */ + +#define M25_MAX_CHIPS		1 +#define AO_M25_SPI_CS_PORT	(&stm_gpioa) +#define AO_M25_SPI_CS_MASK	(1 << 4) +#define AO_M25_SPI_BUS		AO_SPI_1_PA5_PA6_PA7 + +/* MS5607 */ + +#define HAS_MS5607		1 +#define HAS_MS5611		0 +#define AO_MS5607_PRIVATE_PINS	1 +#define AO_MS5607_CS_PORT	(&stm_gpioa) +#define AO_MS5607_CS_PIN	15 +#define AO_MS5607_CS_MASK	(1 << AO_MS5607_CS_PIN) +#define AO_MS5607_MISO_PORT	(&stm_gpiob) +#define AO_MS5607_MISO_PIN	4 +#define AO_MS5607_MISO_MASK	(1 << AO_MS5607_MISO_PIN) +#define AO_MS5607_SPI_INDEX	AO_SPI_1_PB3_PB4_PB5 +#define AO_MS5607_SPI_SPEED	AO_SPI_SPEED_12MHz + +/* CC1200 */ + +// #define AO_RADIO_CAL_DEFAULT 	5695733 +#define AO_RADIO_CAL_DEFAULT 	5695717 + +#define AO_FEC_DEBUG		0 +#define CC1200_DEBUG		0 +#define AO_CC1200_SPI_CS_PORT	(&stm_gpiob) +#define AO_CC1200_SPI_CS_PIN	0 +#define AO_CC1200_SPI_BUS	AO_SPI_1_PA5_PA6_PA7 +#define AO_CC1200_SPI		stm_spi1 +#define AO_CC1200_SPI_SPEED	AO_SPI_SPEED_12MHz + +#define AO_CC1200_INT_PORT		(&stm_gpiob) +#define AO_CC1200_INT_PIN		1 + +#define AO_CC1200_INT_GPIO	2 +#define AO_CC1200_INT_GPIO_IOCFG	CC1200_IOCFG2 + + +#define AO_DATA_RING		16 + +/* + * ADC + */ + +#define HAS_ADC			1 + +#define AO_ADC_PIN0_PORT	(&stm_gpioa)	/* sense_m */ +#define AO_ADC_PIN0_PIN		0 +#define AO_ADC_PIN0_CH		0 +#define AO_ADC_PIN1_PORT	(&stm_gpioa)	/* sense_a */ +#define AO_ADC_PIN1_PIN		1 +#define AO_ADC_PIN1_CH		1 +#define AO_ADC_PIN2_PORT	(&stm_gpioa)	/* v_batt */ +#define AO_ADC_PIN2_PIN		2 +#define AO_ADC_PIN2_CH		2 + +#define AO_ADC_RCC_AHBENR	((1 << STM_RCC_AHBENR_IOPAEN)) + +#define AO_NUM_ADC		3 + +struct ao_adc { +	int16_t		sense_m; +	int16_t		sense_a; +	int16_t		v_batt; +}; + +/* + * Igniter + */ + +#define AO_IGNITER_CLOSED	400 +#define AO_IGNITER_OPEN		60 + +#define AO_IGNITER_DROGUE_PORT	(&stm_gpiob) +#define AO_IGNITER_DROGUE_PIN	7 +#define AO_IGNITER_SET_DROGUE(v)	ao_gpio_set(AO_IGNITER_DROGUE_PORT, AO_IGNITER_DROGUE_PIN, AO_IGNITER_DROGUE, v) + +#define AO_IGNITER_MAIN_PORT	(&stm_gpiob) +#define AO_IGNITER_MAIN_PIN	6 +#define AO_IGNITER_SET_MAIN(v)		ao_gpio_set(AO_IGNITER_MAIN_PORT, AO_IGNITER_MAIN_PIN, AO_IGNITER_MAIN, v) + +#define AO_SENSE_DROGUE(p)	((p)->adc.sense_a) +#define AO_SENSE_MAIN(p)	((p)->adc.sense_m) + +#define AO_ADC_DUMP(p) \ +	printf("tick: %5u apogee: %5d main: %5d batt: %5d\n", \ +	       (p)->tick, (p)->adc.sense_a, (p)->adc.sense_m, (p)->adc.v_batt) + +/* + * Voltage divider on ADC battery sampler + */ +#define AO_BATTERY_DIV_PLUS	56	/* 5.6k */ +#define AO_BATTERY_DIV_MINUS	100	/* 10k */ + +/* + * Voltage divider on ADC igniter samplers + */ +#define AO_IGNITE_DIV_PLUS	100	/* 100k */ +#define AO_IGNITE_DIV_MINUS	27	/* 27k */ + +/* + * ADC reference in decivolts + */ +#define AO_ADC_REFERENCE_DV	33 diff --git a/src/telemini-v3.0/ao_telemini.c b/src/telemini-v3.0/ao_telemini.c new file mode 100644 index 00000000..82c1acd4 --- /dev/null +++ b/src/telemini-v3.0/ao_telemini.c @@ -0,0 +1,58 @@ +/* + * Copyright © 2011 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <ao.h> +#include <ao_exti.h> + +void +main(void) +{ +	ao_clock_init(); +	ao_task_init(); +	ao_timer_init(); + +	ao_dma_init(); +	ao_spi_init(); +	ao_exti_init(); + +	ao_adc_init(); + +#if HAS_BEEP +	ao_beep_init(); +#endif +#if HAS_SERIAL_1 +	ao_serial_init(); +#endif +#if HAS_USB +	ao_usb_init(); +#endif +	ao_cmd_init(); + +	ao_ms5607_init(); + +	ao_storage_init(); +	ao_flight_init(); +	ao_log_init(); +	ao_report_init(); +	ao_telemetry_init(); +	ao_radio_init(); +	ao_packet_slave_init(TRUE); +	ao_igniter_init(); +	ao_config_init(); + +	ao_start_scheduler(); +} diff --git a/src/telemini-v3.0/flash-loader/Makefile b/src/telemini-v3.0/flash-loader/Makefile new file mode 100644 index 00000000..8b628552 --- /dev/null +++ b/src/telemini-v3.0/flash-loader/Makefile @@ -0,0 +1,8 @@ +# +# AltOS flash loader build +# +# + +TOPDIR=../.. +HARDWARE=telemini-v3.0 +include $(TOPDIR)/stmf0/Makefile-flash.defs diff --git a/src/telemini-v3.0/flash-loader/ao_pins.h b/src/telemini-v3.0/flash-loader/ao_pins.h new file mode 100644 index 00000000..fea9a645 --- /dev/null +++ b/src/telemini-v3.0/flash-loader/ao_pins.h @@ -0,0 +1,37 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#include <ao_flash_stm_pins.h> + +/* beeper to 3.3V for boot loader mode */ + +#define AO_BOOT_PIN			1 +#define AO_BOOT_APPLICATION_GPIO	stm_gpioa +#define AO_BOOT_APPLICATION_PIN		3 +#define AO_BOOT_APPLICATION_VALUE	0 +#define AO_BOOT_APPLICATION_MODE	AO_EXTI_MODE_PULL_DOWN + +/* USB */ +#define HAS_USB			1 +#define AO_USB_DIRECTIO		0 +#define AO_PA11_PA12_RMP	1 + +#endif /* _AO_PINS_H_ */ diff --git a/src/test/Makefile b/src/test/Makefile index 02e1d22b..a22abe46 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -1,16 +1,16 @@ -vpath % ..:../kernel:../drivers:../util:../micropeak:../aes:../product +vpath % ..:../kernel:../drivers:../util:../micropeak:../aes:../product:../lisp  PROGS=ao_flight_test ao_flight_test_baro ao_flight_test_accel ao_flight_test_noisy_accel ao_flight_test_mm \  	ao_flight_test_metrum \  	ao_gps_test ao_gps_test_skytraq ao_gps_test_ublox ao_convert_test ao_convert_pa_test ao_fec_test \  	ao_aprs_test ao_micropeak_test ao_fat_test ao_aes_test ao_int64_test \ -	ao_ms5607_convert_test ao_quaternion_test +	ao_ms5607_convert_test ao_quaternion_test ao_lisp_test  INCS=ao_kalman.h ao_ms5607.h ao_log.h ao_data.h altitude-pa.h altitude.h ao_quaternion.h  KALMAN=make-kalman  -CFLAGS=-I.. -I. -I../kernel -I../drivers -I../micropeak -I../product -O0 -g -Wall +CFLAGS=-I.. -I. -I../kernel -I../drivers -I../micropeak -I../product -I../lisp -O0 -g -Wall -DAO_LISP_TEST -no-pie  all: $(PROGS) ao_aprs_data.wav @@ -88,3 +88,12 @@ ao_ms5607_convert_test: ao_ms5607_convert_test.c ao_ms5607_convert_8051.c ao_int  ao_quaternion_test: ao_quaternion_test.c ao_quaternion.h  	cc $(CFLAGS) -o $@ ao_quaternion_test.c -lm +AO_LISP_OBJS = ao_lisp_test.o ao_lisp_mem.o  ao_lisp_cons.o ao_lisp_string.o \ +	ao_lisp_atom.o ao_lisp_int.o ao_lisp_eval.o ao_lisp_poly.o \ +	ao_lisp_builtin.o ao_lisp_read.o ao_lisp_rep.o ao_lisp_frame.o \ +	ao_lisp_lambda.o ao_lisp_error.o ao_lisp_save.o ao_lisp_stack.o + +ao_lisp_test: $(AO_LISP_OBJS) +	cc $(CFLAGS) -o $@ $(AO_LISP_OBJS) + +$(AO_LISP_OBJS): ao_lisp.h ao_lisp_const.h ao_lisp_os.h diff --git a/src/test/ao_aprs_test.c b/src/test/ao_aprs_test.c index 3852668a..941bf954 100644 --- a/src/test/ao_aprs_test.c +++ b/src/test/ao_aprs_test.c @@ -60,6 +60,20 @@ ao_aprs_bit(uint8_t bit)  void  ao_radio_send_aprs(ao_radio_fill_func fill); +static void +aprs_bit_debug(uint8_t tx_bit) +{ +	fprintf (stderr, "bit %d\n", tx_bit); +} + +static void +aprs_byte_debug(uint8_t tx_byte) +{ +	fprintf(stderr, "byte %02x\n", tx_byte); +} +#define APRS_BIT_DEBUG(x) aprs_bit_debug(x) +#define APRS_BYTE_DEBUG(y) aprs_byte_debug(y) +  #include <ao_aprs.c>  /* @@ -103,7 +117,7 @@ audio_gap(int secs)  // This is where we go after reset.  int main(int argc, char **argv)  { -    audio_gap(1); +//    audio_gap(1);      ao_gps_data.latitude = (45.0 + 28.25 / 60.0) * 10000000;      ao_gps_data.longitude = (-(122 + 44.2649 / 60.0)) * 10000000; diff --git a/src/test/ao_flight_test.c b/src/test/ao_flight_test.c index bd7f2ff8..25ddb48f 100644 --- a/src/test/ao_flight_test.c +++ b/src/test/ao_flight_test.c @@ -58,6 +58,7 @@ int ao_gps_new;  #define HAS_HMC5883 		1  #define HAS_BEEP		1  #define AO_CONFIG_MAX_SIZE	1024 +#define AO_MMA655X_INVERT	0  struct ao_adc {  	int16_t			sense[AO_ADC_NUM_SENSE]; @@ -71,6 +72,7 @@ struct ao_adc {  #define AO_ADC_NUM_SENSE	2  #define HAS_MS5607		1  #define HAS_MMA655X		1 +#define AO_MMA655X_INVERT	1  #define HAS_BEEP		1  #define AO_CONFIG_MAX_SIZE	1024 @@ -373,6 +375,8 @@ uint16_t	prev_tick;  #define AO_PYRO_2	2  #define AO_PYRO_3	3 +#define PYRO_DBG	1 +  static void  ao_pyro_pin_set(uint8_t pin, uint8_t value)  { diff --git a/src/test/ao_lisp_os.h b/src/test/ao_lisp_os.h new file mode 100644 index 00000000..9ff2e1fe --- /dev/null +++ b/src/test/ao_lisp_os.h @@ -0,0 +1,59 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_LISP_OS_H_ +#define _AO_LISP_OS_H_ + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + +#define AO_LISP_POOL_TOTAL	3072 +#define AO_LISP_SAVE		1 +#define DBG_MEM_STATS		1 + +extern int ao_lisp_getc(void); + +static inline void +ao_lisp_os_flush() { +	fflush(stdout); +} + +static inline void +ao_lisp_abort(void) +{ +	abort(); +} + +static inline void +ao_lisp_os_led(int led) +{ +	printf("leds set to 0x%x\n", led); +} + +static inline void +ao_lisp_os_delay(int delay) +{ +	if (!delay) +		return; +	struct timespec ts = { +		.tv_sec = delay / 1000, +		.tv_nsec = (delay % 1000) * 1000000, +	}; +	nanosleep(&ts, NULL); +} +#endif diff --git a/src/test/ao_lisp_test.c b/src/test/ao_lisp_test.c new file mode 100644 index 00000000..68e3a202 --- /dev/null +++ b/src/test/ao_lisp_test.c @@ -0,0 +1,134 @@ +/* + * Copyright © 2016 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" +#include <stdio.h> + +static FILE *ao_lisp_file; +static int newline = 1; + +static char save_file[] = "lisp.image"; + +int +ao_lisp_os_save(void) +{ +	FILE	*save = fopen(save_file, "w"); + +	if (!save) { +		perror(save_file); +		return 0; +	} +	fwrite(ao_lisp_pool, 1, AO_LISP_POOL_TOTAL, save); +	fclose(save); +	return 1; +} + +int +ao_lisp_os_restore_save(struct ao_lisp_os_save *save, int offset) +{ +	FILE	*restore = fopen(save_file, "r"); +	size_t	ret; + +	if (!restore) { +		perror(save_file); +		return 0; +	} +	fseek(restore, offset, SEEK_SET); +	ret = fread(save, sizeof (struct ao_lisp_os_save), 1, restore); +	fclose(restore); +	if (ret != 1) +		return 0; +	return 1; +} + +int +ao_lisp_os_restore(void) +{ +	FILE	*restore = fopen(save_file, "r"); +	size_t	ret; + +	if (!restore) { +		perror(save_file); +		return 0; +	} +	ret = fread(ao_lisp_pool, 1, AO_LISP_POOL_TOTAL, restore); +	fclose(restore); +	if (ret != AO_LISP_POOL_TOTAL) +		return 0; +	return 1; +} + +int +ao_lisp_getc(void) +{ +	int c; + +	if (ao_lisp_file) +		return getc(ao_lisp_file); + +	if (newline) { +		printf("> "); +		newline = 0; +	} +	c = getchar(); +	if (c == '\n') +		newline = 1; +	return c; +} + +int +main (int argc, char **argv) +{ +	while (*++argv) { +		ao_lisp_file = fopen(*argv, "r"); +		if (!ao_lisp_file) { +			perror(*argv); +			exit(1); +		} +		ao_lisp_read_eval_print(); +		fclose(ao_lisp_file); +		ao_lisp_file = NULL; +	} +	ao_lisp_read_eval_print(); + +	printf ("collects: full: %d incremental %d\n", +		ao_lisp_collects[AO_LISP_COLLECT_FULL], +		ao_lisp_collects[AO_LISP_COLLECT_INCREMENTAL]); + +	printf ("freed: full %d incremental %d\n", +		ao_lisp_freed[AO_LISP_COLLECT_FULL], +		ao_lisp_freed[AO_LISP_COLLECT_INCREMENTAL]); + +	printf("loops: full %d incremental %d\n", +		ao_lisp_loops[AO_LISP_COLLECT_FULL], +		ao_lisp_loops[AO_LISP_COLLECT_INCREMENTAL]); + +	printf("loops per collect: full %f incremental %f\n", +	       (double) ao_lisp_loops[AO_LISP_COLLECT_FULL] / +	       (double) ao_lisp_collects[AO_LISP_COLLECT_FULL], +	       (double) ao_lisp_loops[AO_LISP_COLLECT_INCREMENTAL] / +	       (double) ao_lisp_collects[AO_LISP_COLLECT_INCREMENTAL]); + +	printf("freed per collect: full %f incremental %f\n", +	       (double) ao_lisp_freed[AO_LISP_COLLECT_FULL] / +	       (double) ao_lisp_collects[AO_LISP_COLLECT_FULL], +	       (double) ao_lisp_freed[AO_LISP_COLLECT_INCREMENTAL] / +	       (double) ao_lisp_collects[AO_LISP_COLLECT_INCREMENTAL]); + +	printf("freed per loop: full %f incremental %f\n", +	       (double) ao_lisp_freed[AO_LISP_COLLECT_FULL] / +	       (double) ao_lisp_loops[AO_LISP_COLLECT_FULL], +	       (double) ao_lisp_freed[AO_LISP_COLLECT_INCREMENTAL] / +	       (double) ao_lisp_loops[AO_LISP_COLLECT_INCREMENTAL]); +} diff --git a/src/test/hanoi.lisp b/src/test/hanoi.lisp new file mode 100644 index 00000000..e2eb0fa0 --- /dev/null +++ b/src/test/hanoi.lisp @@ -0,0 +1,155 @@ +; +; Towers of Hanoi +; +; Copyright © 2016 Keith Packard <keithp@keithp.com> +; +; This program is free software; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, either version 2 of the License, or +; (at your option) any later version. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +; General Public License for more details. +; + +					; ANSI control sequences + +(defun move-to (col row) +  (patom "\033[" row ";" col "H") +  ) + +(defun clear () +  (patom "\033[2J") +  ) + +(defun display-string (x y str) +  (move-to x y) +  (patom str) +  ) + +					; Here's the pieces to display + +(setq stack '("     *     " "    ***    " "   *****   " "  *******  " " ********* " "***********")) + +					; Here's all of the stacks of pieces +					; This is generated when the program is run + +(setq stacks nil) + +					; Display one stack, clearing any +					; space above it + +(defun display-stack (x y clear stack) +  (cond ((= 0 clear) +	 (cond (stack  +		(display-string x y (car stack)) +		(display-stack x (1+ y) 0 (cdr stack)) +		) +	       ) +	 ) +	(t  +	 (display-string x y "                   ") +	 (display-stack x (1+ y) (1- clear) stack) +	 ) +	) +  ) + +					; Position of the top of the stack on the screen +					; Shorter stacks start further down the screen + +(defun stack-pos (y stack) +  (- y (length stack)) +  ) + +					; Display all of the stacks, spaced 20 columns apart + +(defun display-stacks (x y stacks) +  (cond (stacks +	 (display-stack x 0 (stack-pos y (car stacks)) (car stacks)) +	 (display-stacks (+ x 20) y (cdr stacks))) +	) +  ) + +					; Display all of the stacks, then move the cursor +					; out of the way and flush the output + +(defun display () +  (display-stacks 0 top stacks) +  (move-to 1 21) +  (flush) +  ) + +					; Reset stacks to the starting state, with +					; all of the pieces in the first stack and the +					; other two empty + +(defun reset-stacks () +  (setq stacks (list stack nil nil)) +  (setq top (+ (length stack) 3)) +  (length stack) +  ) + +					; more functions which could usefully +					; be in the rom image + +(defun min (a b) +  (cond ((< a b) a) +	(b) +	) +  ) + +					; Replace a stack in the list of stacks +					; with a new value + +(defun replace (list pos member) +  (cond ((= pos 0) (cons member (cdr list))) +	((cons (car list) (replace (cdr list) (1- pos) member))) +	) +  ) + +					; Move a piece from the top of one stack +					; to the top of another + +(setq move-delay 100) + +(defun move-piece (from to) +  (let ((from-stack (nth stacks from)) +	(to-stack (nth stacks to)) +	(piece (car from-stack))) +    (setq from-stack (cdr from-stack)) +    (setq to-stack (cons piece to-stack)) +    (setq stacks (replace stacks from from-stack)) +    (setq stacks (replace stacks to to-stack)) +    (display) +    (delay move-delay) +    ) +  ) + +; The implementation of the game + +(defun _hanoi (n from to use) +  (cond ((= 1 n) +	 (move-piece from to) +	 ) +	(t +	 (_hanoi (1- n) from use to) +	 (_hanoi 1 from to use) +	 (_hanoi (1- n) use to from) +	 ) +	) +  ) + +					; A pretty interface which +					; resets the state of the game, +					; clears the screen and runs +					; the program + +(defun hanoi () +  (setq len (reset-stacks)) +  (clear) +  (_hanoi len 0 1 2) +  (move-to 0 23) +  t +  )  | 
