chiark / gitweb /
wiringpi: much implementation, move pwmc/pwmr
[chiark-tcl.git] / wiringpi / wiringpi.c
index e71cb53ce4831bb04a96fd5662587029e27ff5bc..3b6348d2690890f71b7a6be486d1c894f5178bc3 100644 (file)
  *   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))