chiark / gitweb /
test-load targets: Nicer tracing output from make
[chiark-tcl.git] / wiringpi / wiringpi.c
1 /*
2  * wiringpi setup [MODE]
3  *     MODE is one of -g -1 -p, as for gpio(1)
4  *     optional, if not called is equivalent to saying just "setup"
5  *     may not be called after any other wiringpi use in whole program
6  *     there is no way to un-setup
7  *
8  * Most of the rest are very similar to gpio(1):
9  *   boardRev => integer (see wiringPi.h)
10  *   boardId => [list MODEL REV MEM MAKER OVERVOLTED]
11  *   mode PIN MODE
12  *       MODEs are
13  *             in out pwm pwmTone clock up down tri off
14  *             alt0 alt1 alt2 alt3 alt4 alt5
15  *   read PIN => 0|1
16  *   write PIN 0|1
17  *   aread PIN => VAL
18  *   write PIN VAL
19  *   pwm PIN VAL
20  *   clock PIN FREQ
21  *   pwm-bal|pwm-ms
22  *   pwmr RANGE
23  *   pwmc DIVIDER
24  *   pwmTone PIN FREQ
25  */
26 /* ---8<--- end of documentation comment --8<-- */
27
28 /*
29  * wiringpi.c - wiringPi binding for Tcl
30  * Copyright 2016 Ian Jackson
31  *
32  * This program is free software; you can redistribute it and/or
33  * modify it under the terms of the GNU General Public License as
34  * published by the Free Software Foundation; either version 2 of the
35  * License, or (at your option) any later version.
36  *
37  * This program is distributed in the hope that it will be useful, but
38  * WITHOUT ANY WARRANTY; without even the implied warranty of
39  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
40  * General Public License for more details.
41  *
42  * You should have received a copy of the GNU General Public License
43  * along with this library; if not, see <http://www.gnu.org/licenses/>.
44  */
45
46 #define _GNU_SOURCE
47
48 #include <stdio.h>
49
50 #include "chiark_tcl_wiringpi.h"
51
52 #include "wiringPi.h"
53
54 /*---------- important types and forward declarations ----------*/
55
56 #define CHECK_SETUP                             \
57   int rc;                                       \
58   rc = ensure_setup(ip);                        \
59   if (rc) return rc; else
60
61 #define CHECK_RANGE(val, min, max, what, VAL) do{               \
62     if (val < (min))                                            \
63       return cht_staticerr(ip, what " too small"                \
64                            " (must be at least" #min ")",       \
65                            "WIRINGPI RANGE " VAL " MIN " #min); \
66     if (val > (max))                                            \
67       return cht_staticerr(ip, what " too large"                \
68                            " (must be at most" #max ")",        \
69                            "WIRINGPI RANGE " VAL " MAX " #max); \
70   }while(0)
71
72 static int setup_done;
73
74 /*---------- operations ----------*/
75
76 static int setup_failure(Tcl_Interp *ip, int r) {
77 #define N 4
78   Tcl_Obj *codelist[N];
79   codelist[0]= cht_ret_string(ip,"WIRINGPI");
80   codelist[1]= cht_ret_string(ip,"ERROR");
81   codelist[2]= cht_ret_string(ip,"SETUP");
82   codelist[3]= cht_ret_int(ip,r);
83   Tcl_SetObjResult(ip, Tcl_NewListObj(N, codelist));
84 #undef N
85   Tcl_SetResult(ip, (char*)"wiringpi initialisation error", TCL_STATIC);
86   return TCL_ERROR;
87 }
88
89 static int ensure_setup(Tcl_Interp *ip) {
90   if (!setup_done) {
91     int r = wiringPiSetup();
92     if (r) return setup_failure(ip, r);
93     setup_done = 1;
94   }
95   return TCL_OK;
96 }
97
98 int cht_do_wiringpitcl_setup(ClientData cd, Tcl_Interp *ip,
99                              int objc, Tcl_Obj *const *objv) {
100   int r;
101   int rc;
102
103   if (setup_done)
104     return cht_staticerr(ip,"wiringpi setup called again",
105                          "WIRINGPI FORBIDDEN-REINIT SETUP");
106
107   if (*objv) {
108     const char *modeopt;
109     rc = cht_pat_string(ip,*objv++,&modeopt);
110     if (rc) return rc;
111     if (modeopt[0] != '-' || !modeopt[1] || modeopt[2])
112       return cht_staticerr(ip,"wiringpi setup option wrong syntax", 0);
113     if (*objv)
114       return cht_staticerr(ip,"wiringpi setup too many arguments", 0);
115     switch (modeopt[1]) {
116     case 'g':  r = wiringPiSetupGpio();                             break;
117     case '1':  r = wiringPiSetupPhys();                             break;
118     default:
119       return cht_staticerr(ip,"wiringpi setup option unknown value", 0);
120     }
121   } else {
122     r = wiringPiSetup();
123   }
124   if (r) return setup_failure(ip, r);
125   return TCL_OK;
126 }
127
128 int cht_do_wiringpitcl_boardId(ClientData cd, Tcl_Interp *ip,
129                                Tcl_Obj **result) {
130 #define N 5
131   CHECK_SETUP;
132   int ints[N];
133   Tcl_Obj *objl[N];
134   piBoardId(&ints[0],
135             &ints[1],
136             &ints[2],
137             &ints[3],
138             &ints[4]);
139   int i;
140   for (i=0; i<N; i++) objl[i]= cht_ret_int(ip, ints[i]);
141   *result= Tcl_NewListObj(N,objl);
142   return TCL_OK;
143 #undef N
144 }
145
146 int cht_do_wiringpitcl_boardRev(ClientData cd, Tcl_Interp *ip, int *result) {
147   CHECK_SETUP;
148   *result = piBoardRev();
149   return TCL_OK;
150 }
151
152 int cht_do_wiringpitcl_pwmc(ClientData cd, Tcl_Interp *ip, int divider) {
153   CHECK_SETUP;
154   CHECK_RANGE(divider,1,4095,"divider for pwmc","DIVIDER");
155   pwmSetClock(divider);
156   return TCL_OK;
157 }
158
159 int cht_do_wiringpitcl_pwmr(ClientData cd, Tcl_Interp *ip, int range) {
160   CHECK_SETUP;
161   CHECK_RANGE(range,1,INT_MAX,"pwm range","RANGE");
162   pwmSetRange(range);
163   return TCL_OK;
164 }
165
166 int cht_do_wiringpitcl_pwm_bal(ClientData cd, Tcl_Interp *ip) {
167   CHECK_SETUP;
168   pwmSetMode(PWM_MODE_BAL);
169   return TCL_OK;
170 }
171
172 int cht_do_wiringpitcl_pwm_ms(ClientData cd, Tcl_Interp *ip) {
173   CHECK_SETUP;
174   pwmSetMode(PWM_MODE_MS);
175   return TCL_OK;
176 }
177
178 /*---------- families of operations ----------*/
179
180 #define SIMPLE_READER_OP(op, wpicall)                           \
181   int cht_do_wiringpitcl_##op(ClientData cd, Tcl_Interp *ip,    \
182                                 int pin, int *result) {         \
183     CHECK_SETUP;                                                \
184     *result = wpicall(pin);                                     \
185     return TCL_OK;                                              \
186   }
187
188 SIMPLE_READER_OP(read,  digitalRead)
189 SIMPLE_READER_OP(aread, analogRead)
190
191 #define SIMPLE_WRITER_OP(op, min, max, wpicall)                 \
192   int cht_do_wiringpitcl_##op(ClientData cd, Tcl_Interp *ip,    \
193                               int pin, int val) {               \
194     CHECK_SETUP                                                 \
195     CHECK_RANGE(val,min,max, "value for " #op, "VAL");          \
196     wpicall(pin, val);                                          \
197     return TCL_OK;                                              \
198   }
199
200 SIMPLE_WRITER_OP(pwm,     INT_MIN,INT_MAX, pwmWrite)
201 SIMPLE_WRITER_OP(awrite,  INT_MIN,INT_MAX, analogWrite)
202 SIMPLE_WRITER_OP(write,   0,      1,       digitalWrite)
203 SIMPLE_WRITER_OP(pwmTone, INT_MIN,INT_MAX, pwmToneWrite)
204 SIMPLE_WRITER_OP(clock,   INT_MIN,INT_MAX, gpioClockSet)
205
206 #define MODES(M)                                                \
207   M(in,       { pinMode        (pin, INPUT); })                 \
208   M(input,    { pinMode        (pin, INPUT); })                 \
209   M(out,      { pinMode        (pin, OUTPUT); })                \
210   M(output,   { pinMode        (pin, OUTPUT); })                \
211   M(pwm,      { pinMode        (pin, PWM_OUTPUT); })            \
212   M(pwmTone,  { pinMode        (pin, PWM_TONE_OUTPUT); })       \
213   M(clock,    { pinMode        (pin, GPIO_CLOCK); })            \
214   M(up,       { pullUpDnControl(pin, PUD_UP); })                \
215   M(down,     { pullUpDnControl(pin, PUD_DOWN); })              \
216   M(tri,      { pullUpDnControl(pin, PUD_OFF); })               \
217   M(off,      { pullUpDnControl(pin, PUD_OFF); })               \
218   M(alt0,     { pinModeAlt(pin, 0b100); })                      \
219   M(alt1,     { pinModeAlt(pin, 0b101); })                      \
220   M(alt2,     { pinModeAlt(pin, 0b110); })                      \
221   M(alt3,     { pinModeAlt(pin, 0b111); })                      \
222   M(alt4,     { pinModeAlt(pin, 0b011); })                      \
223   M(alt5,     { pinModeAlt(pin, 0b010); })
224
225 #define MODE_FUNC(name, body) static void mode_##name(int pin) { body }
226   MODES(MODE_FUNC)
227
228 const WiringPiTclModeInfo cht_wiringpitclmodeinfo_entries[] = {
229 #define MODEINFO_ENTRY(name, body) { #name, mode_##name },
230   MODES(MODEINFO_ENTRY)
231   { 0 },
232 };
233
234 int cht_do_wiringpitcl_mode(ClientData cd, Tcl_Interp *ip, int pin,
235                             const WiringPiTclModeInfo *mode) {
236   CHECK_SETUP;
237   mode->func(pin);
238   return TCL_OK;
239 }
240
241
242 /*---------- main hooks for tcl ----------*/
243
244 CHT_INIT(wiringpi, {}, CHTI_COMMANDS(cht_wiringpitoplevel_entries))