* write PIN VAL
* pwm PIN VAL
* clock PIN FREQ
- * drive GROUP VALUE
- * pwm-bal|pwm-ms PIN
- * pwmr PIN RANGE
- * pwmc PIN CLOCK
+ * pwm-bal|pwm-ms
+ * pwmr RANGE
+ * pwmc DIVIDER
* pwmTone PIN FREQ
*/
/* ---8<--- end of documentation comment --8<-- */
#include "chiark_tcl_wiringpi.h"
+#include "wiringPi.h"
+
/*---------- important types and forward declarations ----------*/
+#define CHECK_SETUP \
+ int rc; \
+ rc = ensure_setup(ip); \
+ if (rc) return rc; else
+
+#define CHECK_RANGE(val, min, max, what, VAL) do{ \
+ if (val < (min)) \
+ return cht_staticerr(ip, what " too small" \
+ " (must be at least" #min ")", \
+ "WIRINGPI RANGE " VAL " MIN " #min); \
+ if (val > (max)) \
+ return cht_staticerr(ip, what " too large" \
+ " (must be at most" #max ")", \
+ "WIRINGPI RANGE " VAL " MAX " #max); \
+ }while(0)
+
+static int setup_done;
+
+/*---------- operations ----------*/
+
+static int setup_failure(Tcl_Interp *ip, int r) {
+#define N 4
+ Tcl_Obj *codelist[N];
+ codelist[0]= cht_ret_string(ip,"WIRINGPI");
+ codelist[1]= cht_ret_string(ip,"ERROR");
+ codelist[2]= cht_ret_string(ip,"SETUP");
+ codelist[3]= cht_ret_int(ip,r);
+ Tcl_SetObjResult(ip, Tcl_NewListObj(N, codelist));
+#undef N
+ Tcl_SetResult(ip, (char*)"wiringpi initialisation error", TCL_STATIC);
+ return TCL_ERROR;
+}
+
+static int ensure_setup(Tcl_Interp *ip) {
+ if (!setup_done) {
+ int r = wiringPiSetup();
+ if (r) return setup_failure(ip, r);
+ setup_done = 1;
+ }
+ return TCL_OK;
+}
+
+int cht_do_wiringpitcl_setup(ClientData cd, Tcl_Interp *ip,
+ int objc, Tcl_Obj *const *objv) {
+ int r;
+ int rc;
+
+ if (setup_done)
+ return cht_staticerr(ip,"wiringpi setup called again",
+ "WIRINGPI FORBIDDEN-REINIT SETUP");
+
+ if (*objv) {
+ const char *modeopt;
+ rc = cht_pat_string(ip,*objv++,&modeopt);
+ if (rc) return rc;
+ if (modeopt[0] != '-' || !modeopt[1] || modeopt[2])
+ return cht_staticerr(ip,"wiringpi setup option wrong syntax", 0);
+ if (*objv)
+ return cht_staticerr(ip,"wiringpi setup too many arguments", 0);
+ switch (modeopt[1]) {
+ case 'g': r = wiringPiSetupGpio(); break;
+ case '1': r = wiringPiSetupPhys(); break;
+ default:
+ return cht_staticerr(ip,"wiringpi setup option unknown value", 0);
+ }
+ } else {
+ r = wiringPiSetup();
+ }
+ if (r) return setup_failure(ip, r);
+ return TCL_OK;
+}
+
+int cht_do_wiringpitcl_boardId(ClientData cd, Tcl_Interp *ip,
+ Tcl_Obj **result) {
+#define N 5
+ CHECK_SETUP;
+ int ints[N];
+ Tcl_Obj *objl[N];
+ piBoardId(&ints[0],
+ &ints[1],
+ &ints[2],
+ &ints[3],
+ &ints[4]);
+ int i;
+ for (i=0; i<N; i++) objl[i]= Tcl_NewIntObj(ints[i]);
+ *result= Tcl_NewListObj(N,objl);
+ return TCL_OK;
+#undef N
+}
+
+int cht_do_wiringpitcl_boardRev(ClientData cd, Tcl_Interp *ip, int *result) {
+ CHECK_SETUP;
+ *result = piBoardRev();
+ return TCL_OK;
+}
+
+int cht_do_wiringpitcl_pwmc(ClientData cd, Tcl_Interp *ip, int divider) {
+ CHECK_SETUP;
+ CHECK_RANGE(divider,1,4095,"divider for pwmc","DIVIDER");
+ pwmSetClock(divider);
+ return TCL_OK;
+}
+
+int cht_do_wiringpitcl_pwmr(ClientData cd, Tcl_Interp *ip, int range) {
+ CHECK_SETUP;
+ CHECK_RANGE(range,1,INT_MAX,"pwm range","RANGE");
+ pwmSetRange(range);
+ return TCL_OK;
+}
+
+/*---------- families of operations ----------*/
+
+#define SIMPLE_READER_OP(op, wpicall) \
+ int cht_do_wiringpitcl_##op(ClientData cd, Tcl_Interp *ip, \
+ int pin, int *result) { \
+ CHECK_SETUP; \
+ *result = wpicall(pin); \
+ return TCL_OK; \
+ }
+
+SIMPLE_READER_OP(read, digitalRead)
+SIMPLE_READER_OP(aread, analogRead)
+
+#define SIMPLE_WRITER_OP(op, min, max, wpicall) \
+ int cht_do_wiringpitcl_##op(ClientData cd, Tcl_Interp *ip, \
+ int pin, int val) { \
+ CHECK_SETUP \
+ CHECK_RANGE(val,min,max, "value for " #op, "VAL"); \
+ wpicall(pin, val); \
+ return TCL_OK; \
+ }
+
+SIMPLE_WRITER_OP(pwm, INT_MIN,INT_MAX, pwmWrite)
+SIMPLE_WRITER_OP(awrite, INT_MIN,INT_MAX, analogWrite)
+SIMPLE_WRITER_OP(write, 0, 1, digitalWrite)
+SIMPLE_WRITER_OP(pwmTone, INT_MIN,INT_MAX, pwmToneWrite)
+SIMPLE_WRITER_OP(clock, INT_MIN,INT_MAX, gpioClockSet)
+
+#define MODES(M) \
+ M(in, { pinMode (pin, INPUT); }) \
+ M(input, { pinMode (pin, INPUT); }) \
+ M(out, { pinMode (pin, OUTPUT); }) \
+ M(output, { pinMode (pin, OUTPUT); }) \
+ M(pwm, { pinMode (pin, PWM_OUTPUT); }) \
+ M(pwmTone, { pinMode (pin, PWM_TONE_OUTPUT); }) \
+ M(clock, { pinMode (pin, GPIO_CLOCK); }) \
+ M(up, { pullUpDnControl(pin, PUD_UP); }) \
+ M(down, { pullUpDnControl(pin, PUD_DOWN); }) \
+ M(tri, { pullUpDnControl(pin, PUD_OFF); }) \
+ M(off, { pullUpDnControl(pin, PUD_OFF); }) \
+ M(alt0, { pinModeAlt(pin, 0b100); }) \
+ M(alt1, { pinModeAlt(pin, 0b101); }) \
+ M(alt2, { pinModeAlt(pin, 0b110); }) \
+ M(alt3, { pinModeAlt(pin, 0b111); }) \
+ M(alt4, { pinModeAlt(pin, 0b011); }) \
+ M(alt5, { pinModeAlt(pin, 0b010); })
+
+#define MODE_FUNC(name, body) static void mode_##name(int pin) { body }
+ MODES(MODE_FUNC)
+
+const WiringPiTclModeInfo cht_wiringpitclmodeinfo_entries[] = {
+#define MODEINFO_ENTRY(name, body) { #name, mode_##name },
+ MODES(MODEINFO_ENTRY)
+ { 0 },
+};
+
+int cht_do_wiringpitcl_mode(ClientData cd, Tcl_Interp *ip, int pin,
+ const WiringPiTclModeInfo *mode) {
+ CHECK_SETUP;
+ mode->func(pin);
+ return TCL_OK;
+}
+
+
/*---------- main hooks for tcl ----------*/
CHT_INIT(wiringpi, {}, CHTI_COMMANDS(cht_wiringpitoplevel_entries))