bool Gpio::setStateRange(int state, int startPin, int endPin) { if (!mInit){ fprintf(stderr, "GPIO not initialised\n"); return false; } int pwmVal; if (state == 0) pwmVal = 0; else pwmVal = 100000; for (std::list<Gpio*>::iterator iter = mOutputList.begin(); iter != mOutputList.end(); iter++) { Gpio *obj = *iter; int pin = obj->getPin(); if (obj->getType() == OUT_PIN && pin >= startPin && pin <= endPin) digitalWrite(obj->getPin(), state); } for (auto iter = mMonitorList.begin(); iter != mMonitorList.end(); iter++) { Gpio *obj = *iter; int pin = obj->getPin(); if (obj->getType() == PWM && pin >= startPin && pin <= endPin){ if (mLastValue[pin] != pwmVal) resetPwm(pin, pwmVal); } } return true; }
/** * Start a thread to constantly monitor all the input pins we are * interested in. When a state change is detected we store the * time of the change. This creates a buffer so we can still see * changes that happened a short time ago (so we don't miss any). * * It also writes PWM outputs and is responsible for writing random * data, sine waves etc. to these outputs. */ bool Gpio::startMonitor() { if (!mInit){ fprintf(stderr, "GPIO not initialised\n"); return false; } // Do we have anything to monitor? if (mMonitorList.size() == 0) return true; bool usingPwm = false; for (auto iter = mMonitorList.begin(); iter != mMonitorList.end(); iter++) { Gpio *obj = *iter; int pin = obj->getPin(); if (obj->getType() == PWM){ // Don't start outputting PWM until we execute a relevant command mMonType[pin] = INACTIVE; mMonMutex[pin] = PTHREAD_MUTEX_INITIALIZER; // Set to full range initially (range map is in millis) mRangeMapMin[pin] = 0; mRangeMapMax[pin] = 100000; usingPwm = true; } else { // Input pins are always monitored initMonitorInput(pin); } } if (usingPwm){ // Start ServoBlaster. We use this instead of hardware // PWM as there is only one hardware PWM pin on the Pi // and hardware PWM interferes with analog audio. if (!startServoBlaster()) return false; } // Start monitor thread if (pthread_create(&mMonitorId, NULL, monitor, NULL) != 0){ fprintf(stderr, "** Failed to start gpio monitor\n"); return false; } // Wait for monitor to start for (int retries = 0; retries < 15; retries++){ if (mMonitorRunning) return true; Engine::sleep(200); } printf("** Failed to start gpio monitor\n"); return false; }
bool Gpio::startServoBlaster() { // Stop ServoBlaster if it's already running mServoBlasterPid = Engine::findProcess(SB_COMMAND); if (mServoBlasterPid != -1) stopServoBlaster(); if (Engine::displayOn) printf("Starting ServoBlaster (%s)\n", SB_COMMAND); mServoBlasterPid = fork(); if (mServoBlasterPid == -1){ fprintf(stderr, "** Failed to create ServoBlaster process\n"); return false; } if (mServoBlasterPid != 0){ // This is the parent process // Make sure ServoBlaster started int status; for (int retries = 0; retries < 15; retries++){ if (waitpid(mServoBlasterPid, &status, WNOHANG) != -1){ sleep(1); mServoBlasterOut = open(SB_DEVICE, O_WRONLY|O_SYNC); if (mServoBlasterOut == -1){ fprintf(stderr, "** Failed to open %s\n", SB_DEVICE); return false; } return true; } Engine::sleep(200); } fprintf(stderr, "ServoBlaster failed to start\n"); return false; } // Make ServoBlaster use same pin mapping as wiringPi. // We are mapping wiringPi pin number to physical pin number. const int pinMap[] = {11,12,13,15,16,18,22,7,3,5,24,26,19,21,23,8,10}; int servoBlasterPin[MAX_PWM_PINS]; // ServoBlaster needs to know which pins we are using for PWM for (int i = 0; i < MAX_PWM_PINS; i++) servoBlasterPin[i] = 0; for (auto iter = mMonitorList.begin(); iter != mMonitorList.end(); iter++) { Gpio *obj = *iter; if (obj->getType() == PWM){ int pin = obj->getPin(); servoBlasterPin[pin] = pinMap[pin]; } } // First arg is the pin list char argv1[256]; sprintf(argv1, "--p1pins=%d", servoBlasterPin[0]); char addStr[64]; for (int i = 1; i < MAX_PWM_PINS; i++){ sprintf(addStr, ",%d", servoBlasterPin[i]); strcat(argv1, addStr); } // Second arg is the cycle time char argv2[256]; sprintf(argv2, "--cycle-time=%dus", SB_CYCLE_TIME); const char *argv[16]; argv[0] = SB_COMMAND; argv[1] = argv1; argv[2] = argv2; for (int i = 0;; i++){ argv[i+3] = SB_PARAMS[i]; if (SB_PARAMS[i] == NULL) break; } // redirect stdout and stderr freopen("/tmp/servoblaster.log", "w", stdout); freopen("/tmp/servoblaster.log", "w", stderr); // Try from current dir first char command[256]; sprintf(command, "./%s", SB_COMMAND); execv(command, (char* const*)argv); // execv only returns if an error occurs // Now try from PATH execvp(SB_COMMAND, (char* const*)argv); // execv only returns if an error occurs fprintf(stderr, "** Failed to start ServoBlaster using command:\n"); fprintf(stderr, "%s", SB_COMMAND); for (int i = 0; argv[i] != NULL; i++) fprintf(stderr, " %s", argv[i]); fprintf(stderr, "\n"); return true; }