diff --git a/examples/CppCheesyVisionSample/CheesyVisionRobot/.cproject b/examples/CppCheesyVisionSample/CheesyVisionRobot/.cproject new file mode 100644 index 0000000..2588463 --- /dev/null +++ b/examples/CppCheesyVisionSample/CheesyVisionRobot/.cproject @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/CppCheesyVisionSample/CheesyVisionRobot/.project b/examples/CppCheesyVisionSample/CheesyVisionRobot/.project new file mode 100644 index 0000000..fdfc17c --- /dev/null +++ b/examples/CppCheesyVisionSample/CheesyVisionRobot/.project @@ -0,0 +1,20 @@ + + + CheesyVisionRobot + + + + + + com.windriver.ide.core.wrbuilder + + + + + + com.windriver.ide.core.wrnature + com.windriver.ide.core.wrcorenature + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + + diff --git a/examples/CppCheesyVisionSample/CheesyVisionRobot/.wrmakefile b/examples/CppCheesyVisionSample/CheesyVisionRobot/.wrmakefile new file mode 100644 index 0000000..6ad1e05 --- /dev/null +++ b/examples/CppCheesyVisionSample/CheesyVisionRobot/.wrmakefile @@ -0,0 +1,48 @@ +# The file ".wrmakefile" is the template used by the Wind River Workbench to +# generate the makefiles of this project. Add user-specific build targets and +# make rules only(!) in this project's ".wrmakefile" file. These will then be +# automatically dumped into the makefiles. + +WIND_HOME := $(subst \,/,$(WIND_HOME)) +WIND_BASE := $(subst \,/,$(WIND_BASE)) +WIND_USR := $(subst \,/,$(WIND_USR)) + +all : pre_build main_all post_build + +_clean :: + @echo "make: removing targets and objects of `pwd`" + +%IDE_GENERATED% + +-include $(PRJ_ROOT_DIR)/*.makefile + +-include *.makefile + +main_all : external_build $(PROJECT_TARGETS) + @echo "make: built targets of `pwd`" + +# entry point for extending the build +external_build :: + @echo "" + +# main entry point for pre processing prior to the build +pre_build :: $(PRE_BUILD_STEP) generate_sources + @echo "" + +# entry point for generating sources prior to the build +generate_sources :: + @echo "" + +# main entry point for post processing after the build +post_build :: $(POST_BUILD_STEP) deploy_output + @echo "" + +# entry point for deploying output after the build +deploy_output :: + @echo "" + +clean :: external_clean $(CLEAN_STEP) _clean + +# entry point for extending the build clean +external_clean :: + @echo "" diff --git a/examples/CppCheesyVisionSample/CheesyVisionRobot/.wrproject b/examples/CppCheesyVisionSample/CheesyVisionRobot/.wrproject new file mode 100644 index 0000000..b637f5e --- /dev/null +++ b/examples/CppCheesyVisionSample/CheesyVisionRobot/.wrproject @@ -0,0 +1,258 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/CppCheesyVisionSample/CheesyVisionRobot/CheesyVisionRobot.cpp b/examples/CppCheesyVisionSample/CheesyVisionRobot/CheesyVisionRobot.cpp new file mode 100644 index 0000000..c3e55c5 --- /dev/null +++ b/examples/CppCheesyVisionSample/CheesyVisionRobot/CheesyVisionRobot.cpp @@ -0,0 +1,52 @@ +#include "WPILib.h" +#include "CheesyVisionServer.h" + +class CheesyVisionRobot : public IterativeRobot +{ + CheesyVisionServer *server; +public: + static const int listenPort = 1180; + CheesyVisionRobot() + { + server = CheesyVisionServer::GetInstance(); + } + +void CheesyVisionRobot::RobotInit() { +server->SetPort(listenPort); +server->StartListening(); +} + +void CheesyVisionRobot::DisabledInit() { + server->StopSamplingCounts(); +} + +void CheesyVisionRobot::DisabledPeriodic() { + +} + +void CheesyVisionRobot::AutonomousInit() { + server->Reset(); + server->StartSamplingCounts(); +} + +void CheesyVisionRobot::AutonomousPeriodic() { + printf("Left Status: %d\tRight Status: %d\n", server->GetLeftStatus(), server->GetRightStatus()); + printf("Left Counts: %d\tRight Counts: %d\tTotal Count: %d", server->GetLeftCount(), server->GetRightCount(), server->GetTotalCount()); +} + +void CheesyVisionRobot::TeleopInit() { +} + +void CheesyVisionRobot::TeleopPeriodic() { +} + +void CheesyVisionRobot::TestInit() { +} + +void CheesyVisionRobot::TestPeriodic() { +} + +}; + +START_ROBOT_CLASS(CheesyVisionRobot); + diff --git a/examples/CppCheesyVisionSample/CheesyVisionRobot/CheesyVisionServer.cpp b/examples/CppCheesyVisionSample/CheesyVisionRobot/CheesyVisionServer.cpp new file mode 100644 index 0000000..7fa0ff9 --- /dev/null +++ b/examples/CppCheesyVisionSample/CheesyVisionRobot/CheesyVisionServer.cpp @@ -0,0 +1,103 @@ +#include "CheesyVisionServer.h" +#include "WPILib.h" +#include "networktables2/util/EOFException.h" + +CheesyVisionServer *CheesyVisionServer::_instance = (CheesyVisionServer *) 0; + +#define HEARTBEAT_TIMEOUT 3.0 + +CheesyVisionServer::CheesyVisionServer(int port) +{ + _listenPort = port; + _counting = false; + _curLeftStatus = false; + _curRightStatus = false; + _lastHeartbeatTime = Timer::GetFPGATimestamp(); + _leftCount = 0; + _rightCount = 0; + _totalCount = 0; + _listening = false; + + +} + +void CheesyVisionServer::Run() +{ + if (_listening == false) return; //Make sure we are listening + + SocketServerStreamProvider *sock; + sock = new SocketServerStreamProvider(_listenPort); + while (_listening) + { + IOStream *stream = sock->accept(); + _lastHeartbeatTime = Timer::GetFPGATimestamp(); + try + { + while (Timer::GetFPGATimestamp() < _lastHeartbeatTime + HEARTBEAT_TIMEOUT) + { + try + { + uint8_t byte; + stream->read(&byte, 1); + _curLeftStatus = (byte & (1 << 1)) > 0; + _curRightStatus = (byte & (1 << 0)) > 0; + UpdateCounts(_curLeftStatus,_curRightStatus); + _lastHeartbeatTime = Timer::GetFPGATimestamp(); + } + catch (EOFException e) + { + //End of file, wait for a bit and read some more + + Wait(0.05); + } + + } + } + catch (IOException e) + { + printf("Socket IO error: %s\n", e.what()); + //Catching this exception will dro + } + delete stream;//close, delete and recreate the stream + + Wait(0.05); + } + delete sock; +} + +void CheesyVisionServer::Reset() +{ + _leftCount = 0; + _rightCount = 0; + _totalCount = 0; + + _curLeftStatus = false; + _curRightStatus = false; +} + +void CheesyVisionServer::UpdateCounts(bool left, bool right) +{ + if (true == _counting) + { + _leftCount += left ? 1 : 0; + _rightCount += right ? 1 : 0; + _totalCount++; + } +} + +CheesyVisionServer *CheesyVisionServer::GetInstance() +{ + if (CheesyVisionServer::_instance == (CheesyVisionServer *) 0) + { + CheesyVisionServer::_instance = new CheesyVisionServer(); + } + return CheesyVisionServer::_instance; +} + +bool CheesyVisionServer::HasClientConnection() +{ + return (_lastHeartbeatTime > 0) && (Timer::GetFPGATimestamp() - _lastHeartbeatTime); +} + + + diff --git a/examples/CppCheesyVisionSample/CheesyVisionRobot/CheesyVisionServer.h b/examples/CppCheesyVisionSample/CheesyVisionRobot/CheesyVisionServer.h new file mode 100644 index 0000000..398e273 --- /dev/null +++ b/examples/CppCheesyVisionSample/CheesyVisionRobot/CheesyVisionServer.h @@ -0,0 +1,50 @@ +#include "jankyTask.h" +#include "networktables2/stream/SocketServerStreamProvider.h" + +#ifndef CHEESYVISIONSERVER_H_ +#define CHEESYVISIONSERVER_H_ + + + +class CheesyVisionServer: private JankyTask +{ + + static CheesyVisionServer *_instance; + + + CheesyVisionServer(int port = 1180); + int _listenPort; + + int _leftCount; + int _rightCount; + int _totalCount; + bool _curLeftStatus; + bool _curRightStatus; + bool _counting; + + double _lastHeartbeatTime; + bool _listening; +public: + static CheesyVisionServer *GetInstance(); + bool HasClientConnection(); + void SetPort(int port){_listenPort = port;} + virtual void Run(); + void StartListening(){_listening = true; Start();} + void StopListening(){_listening = false; Pause();} + + void Reset(); + void UpdateCounts(bool left, bool right); + void StartSamplingCounts(){_counting = true;} + void StopSamplingCounts(){_counting = false;} + + bool GetLeftStatus(){return _curLeftStatus;} + bool GetRightStatus(){return _curRightStatus;} + int GetLeftCount(){return _leftCount;} + int GetRightCount(){return _rightCount;} + int GetTotalCount(){return _totalCount;} + + +}; + + +#endif //CHEESYVISIONSERVER_H_ diff --git a/examples/CppCheesyVisionSample/CheesyVisionRobot/jankyTask.cpp b/examples/CppCheesyVisionSample/CheesyVisionRobot/jankyTask.cpp new file mode 100644 index 0000000..b924bc6 --- /dev/null +++ b/examples/CppCheesyVisionSample/CheesyVisionRobot/jankyTask.cpp @@ -0,0 +1,60 @@ +#include "WPILib.h" +#include "jankyTask.h" +#include + +JankyTask::JankyTask(const char* taskName, UINT32 priority) { + std::string name = taskName; + char tmp[30]; + + if (!taskName) + { + sprintf(tmp, "%d", GetFPGATime()); + name = "jankyTask-"; + name += tmp; + } + + enabled_ = false; + running_ = true; + isDead_ = false; + + task_ = new Task(name.c_str(), (FUNCPTR)JankyTask::JankyPrivateStarterTask, priority); + task_->Start((UINT32)this); +} + +JankyTask::~JankyTask(){ + task_->Stop(); + + delete task_; // Now kill the WPI class for the task. +} + +void JankyTask::JankyPrivateStarterTask(JankyTask* task) { + while (task->running_) { + if (task->enabled_) { + task->Run(); + Wait(0.002); // Only wait 2ms when task is active. + } + else + Wait(0.05); // 50 ms wait period while task is 'paused' + } + + task->isDead_ = true; // Falling off the edge of the earth... +} + +void JankyTask::Start() { + enabled_ = true; +} + +void JankyTask::Pause() { + enabled_ = false; +} + +void JankyTask::Terminate() { + running_ = false; + + // Above told the task to exit on the next loop around. + // That could take 2ms or 50ms based on whether it's in pause or run and how long + // the actual Run() routine takes too. So we have to wait until we're really terminated here. + while (!isDead_) { + Wait(0.02); // Wait until we're really dead on that task. + } +} diff --git a/examples/CppCheesyVisionSample/CheesyVisionRobot/jankyTask.h b/examples/CppCheesyVisionSample/CheesyVisionRobot/jankyTask.h new file mode 100644 index 0000000..63e92eb --- /dev/null +++ b/examples/CppCheesyVisionSample/CheesyVisionRobot/jankyTask.h @@ -0,0 +1,64 @@ +#ifndef JANKYTASK_H_ +#define JANKYTASK_H_ + +#include "WPILib.h" + +/** + * @author Robert Wolff - based largely on Tom Bottglieri's work from Team 254 + * @author Tom Bottglieri + * + * @brief Abstract superclass of tasks (run on a separate thread). + * Call Start() to begin the task and Pause() to temporarily pause it. + * The inheriting class must implement Run() which will be called again and + * again when the task is in 'Start/Running' mode. + */ +class JankyTask { + public: + /** + * @brief Constructor which takes an optional taskname. In the absence of a task name, + * a task name will be created based upon the current system-time. + */ + JankyTask(const char* taskName = NULL, UINT32 priority = Task::kDefaultPriority); + virtual ~JankyTask(); + + /** + * @brief PRIVATE- Do not call this function externally as it's only passed to the constructor to initialize the object. + * + * This function sets up an operating-system task which will perpetually loop the Run() function. + * @note When running, loops wait 2ms between calls to Run(). During pause, loop waits 50ms. + * @param JankyTask the given JankyTask object to run. + */ + static void JankyPrivateStarterTask(JankyTask* task); + + /** + * @brief Starts the task. + */ + void Start(); + + /** + * @brief Pauses the task. + */ + void Pause(); + + /** + * @brief Terminate the task. + */ + void Terminate(); + + /** + * @brief The inheriting class must implement this function. This is the function + * which gets run in the new task. + * + * Subclasses should override this function to specify their own behavior. + */ + virtual void Run() = 0; + + bool TaskRunning() {return enabled_;} + private: + bool enabled_; + bool running_; + bool isDead_; + Task* task_; +}; + +#endif // JANKYTASK_H_