From: Callum Date: Sun, 1 Sep 2013 09:55:55 +0000 (+0800) Subject: Merge remote-tracking branch 'upstream/master' X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=519940987ceb9e379c91645daba84dc87680ffb8;hp=496c40213e1cd6eee6cee3f1cabc307c2c893893;p=matches%2FMCTX3420.git Merge remote-tracking branch 'upstream/master' --- diff --git a/camera/.capture.c.swp b/camera/.capture.c.swp deleted file mode 100644 index 9d8f11f..0000000 Binary files a/camera/.capture.c.swp and /dev/null differ diff --git a/irc/log b/irc/log index 73c9654..b954d89 100644 --- a/irc/log +++ b/irc/log @@ -1371,3 +1371,312 @@ 17:07 -!- Irssi: #mctxuwa_softdev: Total of 1 nicks [1 ops, 0 halfops, 0 voices, 0 normal] 17:07 -!- Irssi: Join to #mctxuwa_softdev was synced in 1 secs 17:08 -!- You're now known as sam_moore +--- Day changed Mon Aug 26 2013 +11:11 -!- matches [matches@motsugo.ucc.gu.uwa.edu.au] has joined #mctxuwa_softdev +11:11 -!- matches [matches@motsugo.ucc.gu.uwa.edu.au] has left #mctxuwa_softdev [] +11:12 <@sam_moore> Thought I might have the wrong server +17:18 <@sam_moore> I do have the wrong server! +17:19 -!- sam_moore [matches@motsugo.ucc.gu.uwa.edu.au] has left #mctxuwa_softdev [I have the wrong server!] +--- Log closed Mon Aug 26 17:19:05 2013 +--- Log opened Mon Aug 26 17:19:34 2013 +17:19 -!- sam_moore [matches@motsugo.ucc.gu.uwa.edu.au] has joined #mctxuwa_softdev +17:19 -!- Irssi: #mctxuwa_softdev: Total of 2 nicks [0 ops, 0 halfops, 0 voices, 2 normal] +17:19 -!- Irssi: Join to #mctxuwa_softdev was synced in 5 secs +17:19 < sam_moore> !motd +17:20 < sam_moore> '!motd' +17:20 < sam_moore> MctxBot: You're broken +17:20 < sam_moore> Oh wait, never mind +18:07 -!- jtanx [~asfa@203-59-111-146.dyn.iinet.net.au] has joined #mctxuwa_softdev +18:08 < jtanx> :P +18:09 < jtanx> you can change the message if you want +21:03 -!- jtanx [~asfa@203-59-111-146.dyn.iinet.net.au] has quit ["brb"] +21:12 -!- jtanx [~asfa@203-59-111-146.dyn.iinet.net.au] has joined #mctxuwa_softdev +22:46 -!- jtanx [~asfa@203-59-111-146.dyn.iinet.net.au] has quit ["ChatZilla 0.9.89 [Firefox 23.0.1/20130814063812]"] +--- Day changed Tue Aug 27 2013 +07:40 -!- jtanx [~asfa@203-59-111-146.dyn.iinet.net.au] has joined #mctxuwa_softdev +07:54 -!- jtanx [~asfa@203-59-111-146.dyn.iinet.net.au] has quit ["ChatZilla 0.9.89 [Firefox 23.0.1/20130814063812]"] +17:53 -!- jtanx [~asfa@203-59-111-146.dyn.iinet.net.au] has joined #mctxuwa_softdev +19:11 < jtanx> lol +19:11 < jtanx> the camera that we were using for the soldering lab inserted a bunch of wavy lines/static into the video +19:12 < sam_moore> It's an effect +19:14 < jtanx> nah +19:14 < jtanx> the camera was actually broken +19:15 < sam_moore> (I figured that) +19:15 < sam_moore> You could pretend it's supposed to be an 80s style video? +19:15 < jtanx> yeah that could work +19:16 < jtanx> have you done it yet? +19:18 < sam_moore> No :S +19:20 < jtanx> well +19:21 < jtanx> according to the manual, you need to connect a wire from R5 on the sensor board to the relay board +19:21 < jtanx> problem was we already chopped off the lead on R5 +19:22 < jtanx> another group connected the wire to the LEd though +19:22 < jtanx> seemed to work +20:02 < jtanx> so are we using clock_gettime? +20:08 < sam_moore> I think so, we can use CLOCK_MONOTONIC_RAW if we are paranoid about the system time getting changed +20:08 < sam_moore> Or we can just use CLOCK_REALTIME if we aren't +20:09 < jtanx> I thought CLOCK_MONOTONIC was supposed to be best, because the RAW version wasn't compensated for temp/other stuff +20:10 < jtanx> http://stackoverflow.com/questions/3523442/difference-between-clock-realtime-and-clock-monotonic +20:10 < jtanx> about the FCGI loop blocking +20:10 < jtanx> you can switch to FCGX_ methods +20:10 < jtanx> I think +20:11 < jtanx> but is it really necessary +20:20 < jtanx> about the valgrind comment in sensors.c +20:20 < jtanx> this is probably it: http://stackoverflow.com/questions/5844242/valgrind-yells-about-an-uninitialised-bytes +20:23 < sam_moore> It's probably not necessary to stop the FCGI loop blocking, don't worry about it +20:25 < sam_moore> Yeah, I didn't initialise the buffers anywhere +20:25 < jtanx> actually I can't reproduce that message +20:25 < sam_moore> Hmm +20:26 < jtanx> about the sensor times +20:27 < jtanx> what about if you all reference it relative to some point +20:27 < jtanx> eg +20:27 < sam_moore> The epoch :P +20:27 < jtanx> lol +20:27 < jtanx> I mean +20:28 < jtanx> when you get sensor data, you store the difference in time between the start of recording and now +20:28 < sam_moore> Sure, that makes more sense +20:29 < sam_moore> Just give the client the start of recording time and they can convert it to a time of day / day in the calendar themselves +20:30 < jtanx> yeah +20:30 < jtanx> you could have a specific request to return the starting time +20:30 < jtanx> then it's implicit for all requests +20:30 < jtanx> btw I submitted a pull request for the nginx configs +20:32 < sam_moore> Ok +20:32 < sam_moore> I've added you to collaborators so you can merge them yourself if you need to +20:33 < jtanx> ok +20:35 < jtanx> huh +20:35 < jtanx> http://www.cnx-software.com/2011/09/26/beagleboard-emulator-in-ubuntu-with-qemu/ +20:41 < sam_moore> Nice +20:42 < sam_moore> "Currently you can not access Ethernet" Not so nice +20:42 < sam_moore> Although this is dated 2011 +21:18 -!- jtanx [~asfa@203-59-111-146.dyn.iinet.net.au] has quit ["bye"] +--- Day changed Wed Aug 28 2013 +08:52 -!- jtanx [~asfa@203-59-111-146.dyn.iinet.net.au] has joined #mctxuwa_softdev +10:08 -!- MctxBot [~twang@203-59-111-146.dyn.iinet.net.au] has quit [Connection reset by peer] +10:11 -!- MctxBot [~twang@203-59-111-146.dyn.iinet.net.au] has joined #mctxuwa_softdev +10:39 -!- jtanx [~asfa@203-59-111-146.dyn.iinet.net.au] has quit ["ChatZilla 0.9.89 [Firefox 23.0.1/20130814063812]"] +15:16 -!- jtanx [~asfa@203-59-111-146.dyn.iinet.net.au] has joined #mctxuwa_softdev +15:48 -!- Callum [~chatzilla@124-149-92-17.dyn.iinet.net.au] has joined #mctxuwa_softdev +16:31 < jtanx> huh +16:31 < jtanx> firefox's javascript debugger is pretty cool +16:31 < sam_moore> Firebug? Yeah +16:35 < jtanx> nah the inbuilt one +16:35 < jtanx> firebug's good for inspecting html though +16:35 < jtanx> haven't used firebugs js debugger yet +16:35 < sam_moore> Oh, I didn't know they had an inbuilt one +16:36 < jtanx> Ctrl+Shift+K +16:36 < sam_moore> Of course I normally use Iceweasel, which is currently built as firefox 10.0.2 with a different name +16:36 < jtanx> well that's about 10 releases behind +16:36 < sam_moore> That looks pretty similar to firebug anyway +16:55 < jtanx> inline conditionals in javascript are whack +16:55 -!- Callum_ [~chatzilla@124-149-92-17.dyn.iinet.net.au] has joined #mctxuwa_softdev +16:55 < sam_moore> I haven't done much javascript, but a lot of it does seem whack +16:56 < sam_moore> jtanx: What are you working on in JavaScript? +16:56 < jtanx> unit tests +16:57 < sam_moore> Cool +17:01 -!- Callum [~chatzilla@124-149-92-17.dyn.iinet.net.au] has quit [Ping timeout] +17:01 -!- Callum_ is now known as Callum +17:18 < jtanx> javascript in general is annoying me though +17:25 < Callum> when exactly is this soldering lab due? fucking thing. +17:27 < jtanx> next friday +17:27 < Callum> it says week 5 on lms +17:27 < jtanx> sept 6 +17:27 < Callum> where's it say this? +17:27 < jtanx> yeah he made an announcement +17:27 < jtanx> that it's wrong +17:27 < jtanx> somewhere +17:28 < Callum> sigh. this unit..i swear +17:28 < Callum> if it really is next week then i'd be so relieved +17:28 < Callum> wow +17:28 < Callum> he made an announcement today.. +17:28 < Callum> wait yesterday +17:29 < jtanx> still got that central plant fbd to do +17:29 < Callum> why hasnt LMS emailed me a notification? (/end spam) +17:29 < Callum> yea i know +17:29 < Callum> which i think i have it pretty much done +17:29 < Callum> not 100% sure on it though +17:29 < Callum> and whether to add pumps and shit into it +17:29 < jtanx> what did you have on it? +17:30 < Callum> HA as i say that i check my phone and i have the message about the announcement +17:30 < jtanx> and what did you call the chiller things? +17:30 < Callum> pretty much just the 4 chillers, a line showing it can go back (they're literally called chillers ahha( +17:31 < Callum> then i had another part to show the chillers (evaporation/condensor/compressor and cooling tower is connected to condenser) +17:31 < jtanx> ook +17:31 < Callum> however +17:32 < Callum> im not sure about the input/output of the chiller +17:32 < Callum> because stuff online shows it to be the evaporator +17:32 < Callum> but isnt it water being pumped? +17:32 < jtanx> I think there were pumps on the output +17:33 < jtanx> were there three outputs? +17:33 < Callum> also not sure if i should/wherte to add the tank (yea ofc theres pumps but not sure to put them in to the diagram, pretty much everything is pumped) +17:33 < Callum> outputs where? +17:33 < jtanx> North/Sout/East distribution things +17:33 < jtanx> iirc +17:33 < jtanx> yeah not sure whether to add tank or not +17:34 < Callum> oh that, i didnt bother with that +17:34 < Callum> just how did the chiller connect with the rest of the plant? +17:34 < Callum> was the evaporator the input/output? +17:34 < Callum> because the chiller feeds out to the water tower and the tower feeds back into the chiller (i think) +17:36 < Callum> also what was the thing called? that allowed water to flow back and forth bypassing the chillers. back something? +17:36 < Callum> really they should have told us before we went in we had to do this. some lazy fucks like me dont read the outline so i didnt take notes..or try to commit stuff to memory :po +17:39 < jtanx> the bypass? +17:39 < jtanx> I haven't gone into detail +17:39 < jtanx> so I just have chiller +17:39 < jtanx> and cooling tower +17:39 < jtanx> maybe I should +17:40 < Callum> remember how tehre was 4 chillers, and they would only run what was needed. +17:40 < jtanx> yeah +17:40 < jtanx> how many cooling towers? +17:40 < Callum> and if they had more than they needed there was a pipe to flow back, or if they had some chilled water from the tanks or w.e it bypassed chillers +17:40 < Callum> i dont know, but im not sure how to show it all +17:40 < Callum> im sure what iv got is somewhat decent +17:41 < jtanx> I used visio and I ended up spending so much time trying to get the lines rihgt +17:41 < jtanx> probably would have been faster to hand draw it +17:41 < jtanx> still not finished too +17:41 < Callum> haha im fiarly sure i read somewhere it was hand drawn :p +17:41 < jtanx> meh I suck at drawing +17:42 < Callum> maybe not. "This is to be drawn and annotated on single A4 page" +17:42 < Callum> i dont think they'll be picky +17:42 < jtanx> and there's lines everywhere +17:42 < Callum> really? how do you have lines everywhere? +17:42 < jtanx> ok so chiller +17:42 < Callum> it's a fairly simple system. unless i'v done it wrong :s +17:43 < jtanx> has warm chilled water (1), chilled coolant (2), hot coolant (3), chilled chilled water(4), control line (5), (maybe) sensor back to controller (6) +17:43 < jtanx> that's ~5 lines in/out of one box? +17:44 < Callum> hmm. havent included coolant or control/sensor +17:44 < Callum> maybe i should :S +17:44 < jtanx> and an operator +17:44 < jtanx> to the controller +17:45 < Callum> thing is it asked for a high level FBD though +17:45 < Callum> which means not very detailed +17:45 < Callum> or maybe it didnt? +17:45 < jtanx> yeah, so do you need to show condensor/evaporator +17:45 < jtanx> I just have a chiller box +17:46 < jtanx> anyway... afk ~10 mins +17:46 < Callum> the condensor/evaporater is part of the chiller isnt it? +17:46 < Callum> ok +18:10 < Callum> anyone finished reading chapter 4 of the notes? +18:11 < jtanx> what's that +18:11 < Callum> sensors +18:12 < Callum> so dull :l +18:12 < Callum> and pretty much no chance to remember enough of it. quiz tomorrow is going to be fun.. +18:12 < jtanx> oh +18:13 < jtanx> shit +18:13 < jtanx> have to study for that +18:13 < Callum> rofl +18:14 < jtanx> :/ +18:15 < Callum> gonna just have to wing most of them again like last time most likely. +18:15 < jtanx> probably +18:15 < jtanx> Well, the unit testing thing works http://mctx.us.to:8080/unit-tests/ +18:15 < jtanx> now what unit tests should there be +18:18 < Callum> not sure. +18:25 < Callum> brilliant! the notes show a false colour image built from a black and white image...while printed in black and white. +18:34 < jtanx> :P +19:50 < jtanx> um +19:50 < jtanx> did we get around to doing the sparkplus thing +19:54 < jtanx> we need to do it before the end of the week +19:54 < Callum> umm. +19:54 < Callum> actually justin already set up the group +19:54 < Callum> so you need to hurry up and join before we have to recreate the group :P +19:54 < jtanx> nah it expired +19:54 < Callum> wait already? +19:54 < Callum> zzz +19:55 < jtanx> 5 hr deadline +19:55 < Callum> and adrian said it was 24Hr, whats with this 5 hour shit +19:55 < jtanx> so... we need to try again +19:55 < jtanx> when everyone's available +20:11 -!- Callum [~chatzilla@124-149-92-17.dyn.iinet.net.au] has quit [Ping timeout] +20:49 -!- jtanx [~asfa@203-59-111-146.dyn.iinet.net.au] has quit ["ha"] +--- Day changed Thu Aug 29 2013 +07:47 -!- jtanx [~asfa@203-59-111-146.dyn.iinet.net.au] has joined #mctxuwa_softdev +09:16 < jtanx> firefox blocks ajax calls if you try to run the file locally :/ +09:45 -!- jtanx [~asfa@203-59-111-146.dyn.iinet.net.au] has quit ["ChatZilla 0.9.89 [Firefox 23.0.1/20130814063812]"] +13:33 -!- jtanx [~asfa@203-59-111-146.dyn.iinet.net.au] has joined #mctxuwa_softdev +14:24 -!- james__ [~chatzilla@130.95.133.238] has joined #mctxuwa_softdev +14:25 < james__> Hey Jeremy. Is there a way to find my login hash key if i am already logged into the api? +14:28 < jtanx> um +14:28 < jtanx> right now you should store it +14:29 < jtanx> just declare a global variable and set it to the hash +14:30 < jtanx> or if you have made a class +14:30 < jtanx> just make it an element +14:31 < james__> I'm still logged in from ages ago and i can't logout so i can get a different key that works +14:31 < jtanx> that +14:31 < jtanx> ok +14:31 < james__> Possibly a bug that needs fixing? +14:31 < jtanx> so the way it works right now is there's a 3 minute timeout on the key +14:31 < jtanx> no +14:31 < jtanx> there's actually two layers +14:32 < jtanx> the password that you enter first (mctxadmin) is what's called HTTP basic authentication +14:32 < jtanx> this lets you gain access to /api/login +14:32 < james__> Well i tried loging in again and its saying i am already logged in +14:32 < jtanx> when you reach /api/login you get the access key +14:32 < jtanx> there's a three minute timeout on the key +14:32 < jtanx> if you wish to invalidate the key +14:33 < jtanx> you call +14:33 < jtanx> /api/login?end +14:34 < jtanx> you can force getting a key by also calling /api/login?force +14:34 < james__> right. well it worked this time +14:34 < james__> Thats weird +14:34 < jtanx> so the only thing that the key prevents is stopping accidental concurrent use +14:34 < james__> Fair enough +14:35 < jtanx> Calling /api/login?force will force a new key to be generated and the old one to be invalidated +14:35 < james__> Okay +14:35 < jtanx> btw as I was working on unit testing +14:35 < jtanx> I did a function to retrieve the json data +14:36 < jtanx> http://mctx.us.to:8080/unit-tests/unit-tests.js +14:37 < james__> I will have a look. I have some buttons working and stuff. Working on putting them in a seperate script file for easier editing etc +14:37 < james__> They don't seem to be playing nice at the moment +14:37 < jtanx> ok +14:38 < jtanx> how come it takes so much effort to get some buttons working +14:39 < james__> Getting the css to mesh with the js +14:40 < james__> I have buttons fine +14:40 < james__> And they work +14:40 < jtanx> maybe you should get the functionality to work first +14:40 < jtanx> with the ajax queries +14:40 < jtanx> before worrying about styling them +14:40 < james__> I have the functionality pretty much working +14:41 < jtanx> so the querying works? +14:41 < james__> But i want the styling to work before we scale it up +14:41 < james__> That way its less hassle to fix it later +14:41 < jtanx> could you post it to git? +14:41 < jtanx> it'd be cool to have a look +14:45 < james__> The way i am thinking about having it set out is having a central index.html which just imports all the js. The js will contain all the functionlity seperated in to similar functions. Ie. all the buttons in one script +14:46 < jtanx> right +14:46 < james__> That should allow for ease of scaling and editing +14:46 < james__> Also changing id's and stuff +15:46 -!- james__ [~chatzilla@130.95.133.238] has quit ["ChatZilla 0.9.90.1 [Firefox 23.0.1/20130814063812]"] +19:25 -!- Callum [~chatzilla@124-149-92-17.dyn.iinet.net.au] has joined #mctxuwa_softdev +21:09 -!- jtanx [~asfa@203-59-111-146.dyn.iinet.net.au] has quit ["ChatZilla 0.9.89 [Firefox 23.0.1/20130814063812]"] +23:18 -!- Callum [~chatzilla@124-149-92-17.dyn.iinet.net.au] has quit ["ChatZilla 0.9.90.1 [Firefox 23.0.1/20130814063812]"] +--- Day changed Fri Aug 30 2013 +09:03 -!- jtanx [~asfa@203-59-111-146.dyn.iinet.net.au] has joined #mctxuwa_softdev +09:16 -!- jtanx [~asfa@203-59-111-146.dyn.iinet.net.au] has quit [EOF From client] +14:15 -!- jtanx [~asfa@203-59-111-146.dyn.iinet.net.au] has joined #mctxuwa_softdev +17:06 < jtanx> say you want to perform a command +17:06 < jtanx> eg move an actuator +17:07 < jtanx> and suppose checks have to be made against other sensors to ensure that this command is good to go +17:07 < jtanx> how are those checks going to be made? +18:10 < sam_moore> The Actuator Handler will call some sanity check against the most recent sensor data +18:11 < sam_moore> If they aren't, it will respond with some appropriate JSON or HTTP status code +18:11 < sam_moore> eg: "Try again later when the pressure is in the right range", or "Don't do that you silly person" +18:15 < jtanx> ._. +18:21 < jtanx> I wonder if there's a way to pull from your git repository without creating the 'merge branch master from...' commits +18:22 < sam_moore> I don't think so +18:22 < jtanx> I tried playing with rebasing but it doesn't work out so well +18:40 < jtanx> ok so I've committed some stuff to my repository that changes the handling of controls/actuators/login +18:41 < jtanx> I'm not sure if it's the best way to do it +18:41 < jtanx> though +18:41 < jtanx> What I did was get rid of /api/login +18:41 < jtanx> and instead have /api/control +18:41 < jtanx> All of the control code (eg actuators but may be other controls? Start/stop the whole thing?) has been moved to controls.c +18:42 < jtanx> You still need to supply username and password to access /api/control +18:42 < jtanx> and what was previously called the 'authorization key' is now the control key (ie who has control) +19:00 < sam_moore> Ok, I'll take a look at it later +19:01 < sam_moore> Don't worry about the merge messages, it's not a big deal +19:06 < jtanx> ok thanks +20:27 -!- jtanx [~asfa@203-59-111-146.dyn.iinet.net.au] has quit ["ChatZilla 0.9.90.1 [Firefox 23.0.1/20130814063812]"] +22:21 -!- jtanx [~asfa@203-59-111-146.dyn.iinet.net.au] has joined #mctxuwa_softdev +23:03 -!- jtanx [~asfa@203-59-111-146.dyn.iinet.net.au] has quit ["ChatZilla 0.9.90.1 [Firefox 23.0.1/20130814063812]"] +--- Day changed Sat Aug 31 2013 +09:09 -!- jtanx [~asfa@203-59-111-146.dyn.iinet.net.au] has joined #mctxuwa_softdev +15:30 -!- jtanx [~asfa@203-59-111-146.dyn.iinet.net.au] has quit ["ChatZilla 0.9.90.1 [Firefox 23.0.1/20130814063812]"] +17:40 -!- jtanx [~asfa@203-59-111-146.dyn.iinet.net.au] has joined #mctxuwa_softdev +20:48 -!- jtanx [~asfa@203-59-111-146.dyn.iinet.net.au] has quit ["ChatZilla 0.9.90.1 [Firefox 23.0.1/20130814063812]"] diff --git a/nginx-configs/README b/nginx-configs/README new file mode 100644 index 0000000..1c6ade5 --- /dev/null +++ b/nginx-configs/README @@ -0,0 +1,18 @@ +This folder represents the files that should be placed under: +/etc/nginx + +To install: +* Delete all files under /etc/nginx/sites-enabled +* Either: + * Copy 'mctxconfig' (under sites-enabled) to /etc/nginx/sites-available/ + and create a symlink to that file under /etc/nginx/sites-enabled/ + * Create a symlink directly from 'mctxconfig' to + /etc/etc/nginx/sites-enabled/ +* Replace /etc/nginx/fastcgi_params and /etc/nginx/mime.types with the + provided files (either by copying or symlinking) + +Note: +To get the login functionality working, you need to place a .htpasswd file +under /usr/share/nginx/access (create folder if it doesn't exist). To generate +the htpasswd file, install the apache2-utils package and use the 'htpasswd' +executable. diff --git a/nginx-configs/fastcgi_params b/nginx-configs/fastcgi_params new file mode 100644 index 0000000..51aa692 --- /dev/null +++ b/nginx-configs/fastcgi_params @@ -0,0 +1,27 @@ +fastcgi_param QUERY_STRING $query_string; +fastcgi_param REQUEST_METHOD $request_method; +fastcgi_param CONTENT_TYPE $content_type; +fastcgi_param CONTENT_LENGTH $content_length; + +fastcgi_param SCRIPT_FILENAME $request_filename; +fastcgi_param SCRIPT_NAME $fastcgi_script_name; +fastcgi_param REQUEST_URI $request_uri; +fastcgi_param DOCUMENT_URI $document_uri; +fastcgi_param DOCUMENT_ROOT $document_root; +fastcgi_param SERVER_PROTOCOL $server_protocol; + +fastcgi_param GATEWAY_INTERFACE CGI/1.1; +fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; +fastcgi_param SERVER_HOSTNAME mctxsoft; + +fastcgi_param REMOTE_ADDR $remote_addr; +fastcgi_param REMOTE_PORT $remote_port; +fastcgi_param REMOTE_USER $remote_user; +fastcgi_param SERVER_ADDR $server_addr; +fastcgi_param SERVER_PORT $server_port; +fastcgi_param SERVER_NAME $server_name; + +fastcgi_param HTTPS $https; + +# PHP only, required if PHP was built with --enable-force-cgi-redirect +fastcgi_param REDIRECT_STATUS 200; diff --git a/nginx-configs/mime.types b/nginx-configs/mime.types new file mode 100644 index 0000000..9d05612 --- /dev/null +++ b/nginx-configs/mime.types @@ -0,0 +1,80 @@ +types { + text/html html htm shtml; + text/css css; + text/xml xml rss; + image/gif gif; + image/jpeg jpeg jpg; + application/x-javascript js; + application/atom+xml atom; + + text/mathml mml; + text/plain log; + text/plain txt; + text/vnd.sun.j2me.app-descriptor jad; + text/vnd.wap.wml wml; + text/x-component htc; + + image/png png; + image/tiff tif tiff; + image/vnd.wap.wbmp wbmp; + image/x-icon ico; + image/x-jng jng; + image/x-ms-bmp bmp; + image/svg+xml svg svgz; + + application/java-archive jar war ear; + application/json json; + application/mac-binhex40 hqx; + application/msword doc; + application/pdf pdf; + application/postscript ps eps ai; + application/rtf rtf; + application/vnd.ms-excel xls; + application/vnd.ms-powerpoint ppt; + application/vnd.wap.wmlc wmlc; + application/vnd.google-earth.kml+xml kml; + application/vnd.google-earth.kmz kmz; + application/x-7z-compressed 7z; + application/x-cocoa cco; + application/x-java-archive-diff jardiff; + application/x-java-jnlp-file jnlp; + application/x-makeself run; + application/x-perl pl pm; + application/x-pilot prc pdb; + application/x-rar-compressed rar; + application/x-redhat-package-manager rpm; + application/x-sea sea; + application/x-shockwave-flash swf; + application/x-stuffit sit; + application/x-tcl tcl tk; + application/x-x509-ca-cert der pem crt; + application/x-xpinstall xpi; + application/xhtml+xml xhtml; + application/zip zip; + + application/octet-stream bin exe dll; + application/octet-stream deb; + application/octet-stream dmg; + application/octet-stream eot; + application/octet-stream iso img; + application/octet-stream msi msp msm; + application/ogg ogx; + + audio/midi mid midi kar; + audio/mpeg mpga mpega mp2 mp3 m4a; + audio/ogg oga ogg spx; + audio/x-realaudio ra; + audio/webm weba; + + video/3gpp 3gpp 3gp; + video/mp4 mp4; + video/mpeg mpeg mpg mpe; + video/ogg ogv; + video/quicktime mov; + video/webm webm; + video/x-flv flv; + video/x-mng mng; + video/x-ms-asf asx asf; + video/x-ms-wmv wmv; + video/x-msvideo avi; +} diff --git a/nginx-configs/sites-enabled/mctxconfig b/nginx-configs/sites-enabled/mctxconfig new file mode 100644 index 0000000..541f6d1 --- /dev/null +++ b/nginx-configs/sites-enabled/mctxconfig @@ -0,0 +1,131 @@ +# You may add here your +# server { +# ... +# } +# statements for each of your virtual hosts to this file + +## +# You should look at the following URL's in order to grasp a solid understanding +# of Nginx configuration files in order to fully unleash the power of Nginx. +# http://wiki.nginx.org/Pitfalls +# http://wiki.nginx.org/QuickStart +# http://wiki.nginx.org/Configuration +# +# Generally, you will want to move this file somewhere, and start with a clean +# file but keep this around for reference. Or just disable in sites-enabled. +# +# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples. +## + +server { + listen 80; + listen [::]:80 default_server ipv6only=on; + + root /usr/share/nginx/html; + index index.php index.html index.htm; + + # Make site accessible from http://localhost/ + server_name localhost; + + location / { + # First attempt to serve request as file, then + # as directory, then fall back to displaying a 404. + try_files $uri $uri/ =404; + # Uncomment to enable naxsi on this location + # include /etc/nginx/naxsi.rules + } + + # Only for nginx-naxsi used with nginx-naxsi-ui : process denied requests + #location /RequestDenied { + # proxy_pass http://127.0.0.1:8080; + #} + + #error_page 404 /404.html; + + # redirect server error pages to the static page /50x.html + # + #error_page 500 502 503 504 /50x.html; + #location = /50x.html { + # root /usr/share/nginx/html; + #} + + # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 + # + location ~ \.php$ { + fastcgi_split_path_info ^(.+\.php)(/.+)$; + # # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini + # + # # With php5-cgi alone: + # fastcgi_pass 127.0.0.1:9000; + # # With php5-fpm: + fastcgi_pass unix:/var/run/php5-fpm.sock; + fastcgi_index index.php; + include fastcgi_params; + } + + # deny access to .htaccess files, if Apache's document root + # concurs with nginx's one + # + location ~ /\.ht { + deny all; + } + + #Login area + location ^~ /api/login { + auth_basic "Restricted Access"; + auth_basic_user_file /usr/share/nginx/access/.htpasswd; + + fastcgi_pass 127.0.0.1:9005; + fastcgi_param DOCUMENT_URI_LOCAL login; + include fastcgi_params; + } + + #MCTX API + location /api { + location ~ ^/api/?([^?]*) { + fastcgi_pass 127.0.0.1:9005; + fastcgi_param DOCUMENT_URI_LOCAL $1; + include fastcgi_params; + } + } +} + + +# another virtual host using mix of IP-, name-, and port-based configuration +# +#server { +# listen 8000; +# listen somename:8080; +# server_name somename alias another.alias; +# root html; +# index index.html index.htm; +# +# location / { +# try_files $uri $uri/ =404; +# } +#} + + +# HTTPS server +# +#server { +# listen 443; +# server_name localhost; +# +# root html; +# index index.html index.htm; +# +# ssl on; +# ssl_certificate cert.pem; +# ssl_certificate_key cert.key; +# +# ssl_session_timeout 5m; +# +# ssl_protocols SSLv3 TLSv1; +# ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv3:+EXP; +# ssl_prefer_server_ciphers on; +# +# location / { +# try_files $uri $uri/ =404; +# } +#} diff --git a/sensors/beagleboard sensors notes.docx b/sensors/beagleboard sensors notes.docx new file mode 100644 index 0000000..746600c Binary files /dev/null and b/sensors/beagleboard sensors notes.docx differ diff --git a/sensors/sensors test drivers (c)/generic_buffer.c b/sensors/sensors test drivers (c)/generic_buffer.c new file mode 100644 index 0000000..40d0eca --- /dev/null +++ b/sensors/sensors test drivers (c)/generic_buffer.c @@ -0,0 +1,340 @@ +/* Industrialio buffer test code. + * + * Copyright (c) 2008 Jonathan Cameron + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is primarily intended as an example application. + * Reads the current buffer setup from sysfs and starts a short capture + * from the specified device, pretty printing the result after appropriate + * conversion. + * + * Command line parameters + * generic_buffer -n -t + * If trigger name is not specified the program assumes you want a dataready + * trigger associated with the device and goes looking for it. + * + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "iio_utils.h" + +/** + * size_from_channelarray() - calculate the storage size of a scan + * @channels: the channel info array + * @num_channels: number of channels + * + * Has the side effect of filling the channels[i].location values used + * in processing the buffer output. + **/ +int size_from_channelarray(struct iio_channel_info *channels, int num_channels) +{ + int bytes = 0; + int i = 0; + while (i < num_channels) { + if (bytes % channels[i].bytes == 0) + channels[i].location = bytes; + else + channels[i].location = bytes - bytes%channels[i].bytes + + channels[i].bytes; + bytes = channels[i].location + channels[i].bytes; + i++; + } + return bytes; +} + +void print2byte(int input, struct iio_channel_info *info) +{ + /* First swap if incorrect endian */ + if (info->be) + input = be16toh((uint16_t)input); + else + input = le16toh((uint16_t)input); + + /* + * Shift before conversion to avoid sign extension + * of left aligned data + */ + input = input >> info->shift; + if (info->is_signed) { + int16_t val = input; + val &= (1 << info->bits_used) - 1; + val = (int16_t)(val << (16 - info->bits_used)) >> + (16 - info->bits_used); + printf("%05f ", ((float)val + info->offset)*info->scale); + } else { + uint16_t val = input; + val &= (1 << info->bits_used) - 1; + printf("%05f ", ((float)val + info->offset)*info->scale); + } +} +/** + * process_scan() - print out the values in SI units + * @data: pointer to the start of the scan + * @channels: information about the channels. Note + * size_from_channelarray must have been called first to fill the + * location offsets. + * @num_channels: number of channels + **/ +void process_scan(char *data, + struct iio_channel_info *channels, + int num_channels) +{ + int k; + for (k = 0; k < num_channels; k++) + switch (channels[k].bytes) { + /* only a few cases implemented so far */ + case 2: + print2byte(*(uint16_t *)(data + channels[k].location), + &channels[k]); + break; + case 4: + if (!channels[k].is_signed) { + uint32_t val = *(uint32_t *) + (data + channels[k].location); + printf("%05f ", ((float)val + + channels[k].offset)* + channels[k].scale); + + } + break; + case 8: + if (channels[k].is_signed) { + int64_t val = *(int64_t *) + (data + + channels[k].location); + if ((val >> channels[k].bits_used) & 1) + val = (val & channels[k].mask) | + ~channels[k].mask; + /* special case for timestamp */ + if (channels[k].scale == 1.0f && + channels[k].offset == 0.0f) + printf("%" PRId64 " ", val); + else + printf("%05f ", ((float)val + + channels[k].offset)* + channels[k].scale); + } + break; + default: + break; + } + printf("\n"); +} + +int main(int argc, char **argv) +{ + unsigned long num_loops = 2; + unsigned long timedelay = 1000000; + unsigned long buf_len = 128; + + int ret, c, i, j, toread; + int fp; + + int num_channels; + char *trigger_name = NULL, *device_name = NULL; + char *dev_dir_name, *buf_dir_name; + + int datardytrigger = 1; + char *data; + ssize_t read_size; + int dev_num, trig_num; + char *buffer_access; + int scan_size; + int noevents = 0; + char *dummy; + + struct iio_channel_info *channels; + + while ((c = getopt(argc, argv, "l:w:c:et:n:")) != -1) { + switch (c) { + case 'n': + device_name = optarg; + break; + case 't': + trigger_name = optarg; + datardytrigger = 0; + break; + case 'e': + noevents = 1; + break; + case 'c': + num_loops = strtoul(optarg, &dummy, 10); + break; + case 'w': + timedelay = strtoul(optarg, &dummy, 10); + break; + case 'l': + buf_len = strtoul(optarg, &dummy, 10); + break; + case '?': + return -1; + } + } + + if (device_name == NULL) + return -1; + + /* Find the device requested */ + dev_num = find_type_by_name(device_name, "iio:device"); + if (dev_num < 0) { + printf("Failed to find the %s\n", device_name); + ret = -ENODEV; + goto error_ret; + } + printf("iio device number being used is %d\n", dev_num); + + asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num); + if (trigger_name == NULL) { + /* + * Build the trigger name. If it is device associated its + * name is _dev[n] where n matches the device + * number found above + */ + ret = asprintf(&trigger_name, + "%s-dev%d", device_name, dev_num); + if (ret < 0) { + ret = -ENOMEM; + goto error_ret; + } + } + + /* Verify the trigger exists */ + trig_num = find_type_by_name(trigger_name, "trigger"); + if (trig_num < 0) { + printf("Failed to find the trigger %s\n", trigger_name); + ret = -ENODEV; + goto error_free_triggername; + } + printf("iio trigger number being used is %d\n", trig_num); + + /* + * Parse the files in scan_elements to identify what channels are + * present + */ + ret = build_channel_array(dev_dir_name, &channels, &num_channels); + if (ret) { + printf("Problem reading scan element information\n"); + printf("diag %s\n", dev_dir_name); + goto error_free_triggername; + } + + /* + * Construct the directory name for the associated buffer. + * As we know that the lis3l02dq has only one buffer this may + * be built rather than found. + */ + ret = asprintf(&buf_dir_name, + "%siio:device%d/buffer", iio_dir, dev_num); + if (ret < 0) { + ret = -ENOMEM; + goto error_free_triggername; + } + printf("%s %s\n", dev_dir_name, trigger_name); + /* Set the device trigger to be the data ready trigger found above */ + ret = write_sysfs_string_and_verify("trigger/current_trigger", + dev_dir_name, + trigger_name); + if (ret < 0) { + printf("Failed to write current_trigger file\n"); + goto error_free_buf_dir_name; + } + + /* Setup ring buffer parameters */ + ret = write_sysfs_int("length", buf_dir_name, buf_len); + if (ret < 0) + goto error_free_buf_dir_name; + + /* Enable the buffer */ + ret = write_sysfs_int("enable", buf_dir_name, 1); + if (ret < 0) + goto error_free_buf_dir_name; + scan_size = size_from_channelarray(channels, num_channels); + data = malloc(scan_size*buf_len); + if (!data) { + ret = -ENOMEM; + goto error_free_buf_dir_name; + } + + ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num); + if (ret < 0) { + ret = -ENOMEM; + goto error_free_data; + } + + /* Attempt to open non blocking the access dev */ + fp = open(buffer_access, O_RDONLY | O_NONBLOCK); + if (fp == -1) { /* If it isn't there make the node */ + printf("Failed to open %s\n", buffer_access); + ret = -errno; + goto error_free_buffer_access; + } + + /* Wait for events 10 times */ + for (j = 0; j < num_loops; j++) { + if (!noevents) { + struct pollfd pfd = { + .fd = fp, + .events = POLLIN, + }; + + poll(&pfd, 1, -1); + toread = buf_len; + + } else { + usleep(timedelay); + toread = 64; + } + + read_size = read(fp, + data, + toread*scan_size); + if (read_size == -EAGAIN) { + printf("nothing available\n"); + continue; + } + for (i = 0; i < read_size/scan_size; i++) + process_scan(data + scan_size*i, + channels, + num_channels); + } + + /* Stop the buffer */ + ret = write_sysfs_int("enable", buf_dir_name, 0); + if (ret < 0) + goto error_close_buffer_access; + + /* Disconnect the trigger - just write a dummy name. */ + write_sysfs_string("trigger/current_trigger", + dev_dir_name, "NULL"); + +error_close_buffer_access: + close(fp); +error_free_data: + free(data); +error_free_buffer_access: + free(buffer_access); +error_free_buf_dir_name: + free(buf_dir_name); +error_free_triggername: + if (datardytrigger) + free(trigger_name); +error_ret: + return ret; +} diff --git a/sensors/sensors test drivers (c)/iio_utils.h b/sensors/sensors test drivers (c)/iio_utils.h new file mode 100644 index 0000000..cf32ae0 --- /dev/null +++ b/sensors/sensors test drivers (c)/iio_utils.h @@ -0,0 +1,654 @@ +/* IIO - useful set of util functionality + * + * Copyright (c) 2008 Jonathan Cameron + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Made up value to limit allocation sizes */ +#define IIO_MAX_NAME_LENGTH 30 + +#define FORMAT_SCAN_ELEMENTS_DIR "%s/scan_elements" +#define FORMAT_TYPE_FILE "%s_type" + +const char *iio_dir = "/sys/bus/iio/devices/"; + +/** + * iioutils_break_up_name() - extract generic name from full channel name + * @full_name: the full channel name + * @generic_name: the output generic channel name + **/ +inline int iioutils_break_up_name(const char *full_name, + char **generic_name) +{ + char *current; + char *w, *r; + char *working; + current = strdup(full_name); + working = strtok(current, "_\0"); + w = working; + r = working; + + while (*r != '\0') { + if (!isdigit(*r)) { + *w = *r; + w++; + } + r++; + } + *w = '\0'; + *generic_name = strdup(working); + free(current); + + return 0; +} + +/** + * struct iio_channel_info - information about a given channel + * @name: channel name + * @generic_name: general name for channel type + * @scale: scale factor to be applied for conversion to si units + * @offset: offset to be applied for conversion to si units + * @index: the channel index in the buffer output + * @bytes: number of bytes occupied in buffer output + * @mask: a bit mask for the raw output + * @is_signed: is the raw value stored signed + * @enabled: is this channel enabled + **/ +struct iio_channel_info { + char *name; + char *generic_name; + float scale; + float offset; + unsigned index; + unsigned bytes; + unsigned bits_used; + unsigned shift; + uint64_t mask; + unsigned be; + unsigned is_signed; + unsigned enabled; + unsigned location; +}; + +/** + * iioutils_get_type() - find and process _type attribute data + * @is_signed: output whether channel is signed + * @bytes: output how many bytes the channel storage occupies + * @mask: output a bit mask for the raw data + * @be: big endian + * @device_dir: the iio device directory + * @name: the channel name + * @generic_name: the channel type name + **/ +inline int iioutils_get_type(unsigned *is_signed, + unsigned *bytes, + unsigned *bits_used, + unsigned *shift, + uint64_t *mask, + unsigned *be, + const char *device_dir, + const char *name, + const char *generic_name) +{ + FILE *sysfsfp; + int ret; + DIR *dp; + char *scan_el_dir, *builtname, *builtname_generic, *filename = 0; + char signchar, endianchar; + unsigned padint; + const struct dirent *ent; + + ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); + if (ret < 0) { + ret = -ENOMEM; + goto error_ret; + } + ret = asprintf(&builtname, FORMAT_TYPE_FILE, name); + if (ret < 0) { + ret = -ENOMEM; + goto error_free_scan_el_dir; + } + ret = asprintf(&builtname_generic, FORMAT_TYPE_FILE, generic_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_free_builtname; + } + + dp = opendir(scan_el_dir); + if (dp == NULL) { + ret = -errno; + goto error_free_builtname_generic; + } + while (ent = readdir(dp), ent != NULL) + /* + * Do we allow devices to override a generic name with + * a specific one? + */ + if ((strcmp(builtname, ent->d_name) == 0) || + (strcmp(builtname_generic, ent->d_name) == 0)) { + ret = asprintf(&filename, + "%s/%s", scan_el_dir, ent->d_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_closedir; + } + sysfsfp = fopen(filename, "r"); + if (sysfsfp == NULL) { + printf("failed to open %s\n", filename); + ret = -errno; + goto error_free_filename; + } + + ret = fscanf(sysfsfp, + "%ce:%c%u/%u>>%u", + &endianchar, + &signchar, + bits_used, + &padint, shift); + if (ret < 0) { + printf("failed to pass scan type description\n"); + ret = -errno; + goto error_close_sysfsfp; + } + *be = (endianchar == 'b'); + *bytes = padint / 8; + if (*bits_used == 64) + *mask = ~0; + else + *mask = (1 << *bits_used) - 1; + if (signchar == 's') + *is_signed = 1; + else + *is_signed = 0; + fclose(sysfsfp); + free(filename); + + filename = 0; + sysfsfp = 0; + } +error_close_sysfsfp: + if (sysfsfp) + fclose(sysfsfp); +error_free_filename: + if (filename) + free(filename); +error_closedir: + closedir(dp); +error_free_builtname_generic: + free(builtname_generic); +error_free_builtname: + free(builtname); +error_free_scan_el_dir: + free(scan_el_dir); +error_ret: + return ret; +} + +inline int iioutils_get_param_float(float *output, + const char *param_name, + const char *device_dir, + const char *name, + const char *generic_name) +{ + FILE *sysfsfp; + int ret; + DIR *dp; + char *builtname, *builtname_generic; + char *filename = NULL; + const struct dirent *ent; + + ret = asprintf(&builtname, "%s_%s", name, param_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_ret; + } + ret = asprintf(&builtname_generic, + "%s_%s", generic_name, param_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_free_builtname; + } + dp = opendir(device_dir); + if (dp == NULL) { + ret = -errno; + goto error_free_builtname_generic; + } + while (ent = readdir(dp), ent != NULL) + if ((strcmp(builtname, ent->d_name) == 0) || + (strcmp(builtname_generic, ent->d_name) == 0)) { + ret = asprintf(&filename, + "%s/%s", device_dir, ent->d_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_closedir; + } + sysfsfp = fopen(filename, "r"); + if (!sysfsfp) { + ret = -errno; + goto error_free_filename; + } + fscanf(sysfsfp, "%f", output); + break; + } +error_free_filename: + if (filename) + free(filename); +error_closedir: + closedir(dp); +error_free_builtname_generic: + free(builtname_generic); +error_free_builtname: + free(builtname); +error_ret: + return ret; +} + +/** + * bsort_channel_array_by_index() - reorder so that the array is in index order + * + **/ + +inline void bsort_channel_array_by_index(struct iio_channel_info **ci_array, + int cnt) +{ + + struct iio_channel_info temp; + int x, y; + + for (x = 0; x < cnt; x++) + for (y = 0; y < (cnt - 1); y++) + if ((*ci_array)[y].index > (*ci_array)[y+1].index) { + temp = (*ci_array)[y + 1]; + (*ci_array)[y + 1] = (*ci_array)[y]; + (*ci_array)[y] = temp; + } +} + +/** + * build_channel_array() - function to figure out what channels are present + * @device_dir: the IIO device directory in sysfs + * @ + **/ +inline int build_channel_array(const char *device_dir, + struct iio_channel_info **ci_array, + int *counter) +{ + DIR *dp; + FILE *sysfsfp; + int count, i; + struct iio_channel_info *current; + int ret; + const struct dirent *ent; + char *scan_el_dir; + char *filename; + + *counter = 0; + ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); + if (ret < 0) { + ret = -ENOMEM; + goto error_ret; + } + dp = opendir(scan_el_dir); + if (dp == NULL) { + ret = -errno; + goto error_free_name; + } + while (ent = readdir(dp), ent != NULL) + if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), + "_en") == 0) { + ret = asprintf(&filename, + "%s/%s", scan_el_dir, ent->d_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_close_dir; + } + sysfsfp = fopen(filename, "r"); + if (sysfsfp == NULL) { + ret = -errno; + free(filename); + goto error_close_dir; + } + fscanf(sysfsfp, "%u", &ret); + if (ret == 1) + (*counter)++; + fclose(sysfsfp); + free(filename); + } + *ci_array = malloc(sizeof(**ci_array) * (*counter)); + if (*ci_array == NULL) { + ret = -ENOMEM; + goto error_close_dir; + } + seekdir(dp, 0); + count = 0; + while (ent = readdir(dp), ent != NULL) { + if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), + "_en") == 0) { + current = &(*ci_array)[count++]; + ret = asprintf(&filename, + "%s/%s", scan_el_dir, ent->d_name); + if (ret < 0) { + ret = -ENOMEM; + /* decrement count to avoid freeing name */ + count--; + goto error_cleanup_array; + } + sysfsfp = fopen(filename, "r"); + if (sysfsfp == NULL) { + free(filename); + ret = -errno; + goto error_cleanup_array; + } + fscanf(sysfsfp, "%u", ¤t->enabled); + fclose(sysfsfp); + + if (!current->enabled) { + free(filename); + count--; + continue; + } + + current->scale = 1.0; + current->offset = 0; + current->name = strndup(ent->d_name, + strlen(ent->d_name) - + strlen("_en")); + if (current->name == NULL) { + free(filename); + ret = -ENOMEM; + goto error_cleanup_array; + } + /* Get the generic and specific name elements */ + ret = iioutils_break_up_name(current->name, + ¤t->generic_name); + if (ret) { + free(filename); + goto error_cleanup_array; + } + ret = asprintf(&filename, + "%s/%s_index", + scan_el_dir, + current->name); + if (ret < 0) { + free(filename); + ret = -ENOMEM; + goto error_cleanup_array; + } + sysfsfp = fopen(filename, "r"); + fscanf(sysfsfp, "%u", ¤t->index); + fclose(sysfsfp); + free(filename); + /* Find the scale */ + ret = iioutils_get_param_float(¤t->scale, + "scale", + device_dir, + current->name, + current->generic_name); + if (ret < 0) + goto error_cleanup_array; + ret = iioutils_get_param_float(¤t->offset, + "offset", + device_dir, + current->name, + current->generic_name); + if (ret < 0) + goto error_cleanup_array; + ret = iioutils_get_type(¤t->is_signed, + ¤t->bytes, + ¤t->bits_used, + ¤t->shift, + ¤t->mask, + ¤t->be, + device_dir, + current->name, + current->generic_name); + } + } + + closedir(dp); + /* reorder so that the array is in index order */ + bsort_channel_array_by_index(ci_array, *counter); + + return 0; + +error_cleanup_array: + for (i = count - 1; i >= 0; i--) + free((*ci_array)[i].name); + free(*ci_array); +error_close_dir: + closedir(dp); +error_free_name: + free(scan_el_dir); +error_ret: + return ret; +} + +/** + * find_type_by_name() - function to match top level types by name + * @name: top level type instance name + * @type: the type of top level instance being sort + * + * Typical types this is used for are device and trigger. + **/ +inline int find_type_by_name(const char *name, const char *type) +{ + const struct dirent *ent; + int number, numstrlen; + + FILE *nameFile; + DIR *dp; + char thisname[IIO_MAX_NAME_LENGTH]; + char *filename; + + dp = opendir(iio_dir); + if (dp == NULL) { + printf("No industrialio devices available\n"); + return -ENODEV; + } + + while (ent = readdir(dp), ent != NULL) { + if (strcmp(ent->d_name, ".") != 0 && + strcmp(ent->d_name, "..") != 0 && + strlen(ent->d_name) > strlen(type) && + strncmp(ent->d_name, type, strlen(type)) == 0) { + numstrlen = sscanf(ent->d_name + strlen(type), + "%d", + &number); + /* verify the next character is not a colon */ + if (strncmp(ent->d_name + strlen(type) + numstrlen, + ":", + 1) != 0) { + filename = malloc(strlen(iio_dir) + + strlen(type) + + numstrlen + + 6); + if (filename == NULL) { + closedir(dp); + return -ENOMEM; + } + sprintf(filename, "%s%s%d/name", + iio_dir, + type, + number); + nameFile = fopen(filename, "r"); + if (!nameFile) { + free(filename); + continue; + } + free(filename); + fscanf(nameFile, "%s", thisname); + fclose(nameFile); + if (strcmp(name, thisname) == 0) { + closedir(dp); + return number; + } + } + } + } + closedir(dp); + return -ENODEV; +} + +inline int _write_sysfs_int(char *filename, char *basedir, int val, int verify) +{ + int ret; + FILE *sysfsfp; + int test; + char *temp = malloc(strlen(basedir) + strlen(filename) + 2); + if (temp == NULL) + return -ENOMEM; + sprintf(temp, "%s/%s", basedir, filename); + sysfsfp = fopen(temp, "w"); + if (sysfsfp == NULL) { + printf("failed to open %s\n", temp); + ret = -errno; + goto error_free; + } + fprintf(sysfsfp, "%d", val); + fclose(sysfsfp); + if (verify) { + sysfsfp = fopen(temp, "r"); + if (sysfsfp == NULL) { + printf("failed to open %s\n", temp); + ret = -errno; + goto error_free; + } + fscanf(sysfsfp, "%d", &test); + fclose(sysfsfp); + if (test != val) { + printf("Possible failure in int write %d to %s%s\n", + val, + basedir, + filename); + ret = -1; + } + } +error_free: + free(temp); + return ret; +} + +int write_sysfs_int(char *filename, char *basedir, int val) +{ + return _write_sysfs_int(filename, basedir, val, 0); +} + +int write_sysfs_int_and_verify(char *filename, char *basedir, int val) +{ + return _write_sysfs_int(filename, basedir, val, 1); +} + +int _write_sysfs_string(char *filename, char *basedir, char *val, int verify) +{ + int ret = 0; + FILE *sysfsfp; + char *temp = malloc(strlen(basedir) + strlen(filename) + 2); + if (temp == NULL) { + printf("Memory allocation failed\n"); + return -ENOMEM; + } + sprintf(temp, "%s/%s", basedir, filename); + sysfsfp = fopen(temp, "w"); + if (sysfsfp == NULL) { + printf("Could not open %s\n", temp); + ret = -errno; + goto error_free; + } + fprintf(sysfsfp, "%s", val); + fclose(sysfsfp); + if (verify) { + sysfsfp = fopen(temp, "r"); + if (sysfsfp == NULL) { + printf("could not open file to verify\n"); + ret = -errno; + goto error_free; + } + fscanf(sysfsfp, "%s", temp); + fclose(sysfsfp); + if (strcmp(temp, val) != 0) { + printf("Possible failure in string write of %s " + "Should be %s " + "written to %s\%s\n", + temp, + val, + basedir, + filename); + ret = -1; + } + } +error_free: + free(temp); + + return ret; +} + +/** + * write_sysfs_string_and_verify() - string write, readback and verify + * @filename: name of file to write to + * @basedir: the sysfs directory in which the file is to be found + * @val: the string to write + **/ +int write_sysfs_string_and_verify(char *filename, char *basedir, char *val) +{ + return _write_sysfs_string(filename, basedir, val, 1); +} + +int write_sysfs_string(char *filename, char *basedir, char *val) +{ + return _write_sysfs_string(filename, basedir, val, 0); +} + +int read_sysfs_posint(char *filename, char *basedir) +{ + int ret; + FILE *sysfsfp; + char *temp = malloc(strlen(basedir) + strlen(filename) + 2); + if (temp == NULL) { + printf("Memory allocation failed"); + return -ENOMEM; + } + sprintf(temp, "%s/%s", basedir, filename); + sysfsfp = fopen(temp, "r"); + if (sysfsfp == NULL) { + ret = -errno; + goto error_free; + } + fscanf(sysfsfp, "%d\n", &ret); + fclose(sysfsfp); +error_free: + free(temp); + return ret; +} + +int read_sysfs_float(char *filename, char *basedir, float *val) +{ + float ret = 0; + FILE *sysfsfp; + char *temp = malloc(strlen(basedir) + strlen(filename) + 2); + if (temp == NULL) { + printf("Memory allocation failed"); + return -ENOMEM; + } + sprintf(temp, "%s/%s", basedir, filename); + sysfsfp = fopen(temp, "r"); + if (sysfsfp == NULL) { + ret = -errno; + goto error_free; + } + fscanf(sysfsfp, "%f\n", val); + fclose(sysfsfp); +error_free: + free(temp); + return ret; +} diff --git a/sensors/sensors test drivers (c)/readme.txt b/sensors/sensors test drivers (c)/readme.txt new file mode 100644 index 0000000..80ca9a3 --- /dev/null +++ b/sensors/sensors test drivers (c)/readme.txt @@ -0,0 +1,20 @@ +This is a userspace application which accesses the adc via /dev/iio in continuous sampling mode. + +The application scans the scan_elements folder in /dev/iio/devices/iio:deviceX/scan_elements for enabled channels. + +Creates a data structure. + +Sets the buffer size. Enables the buffer. And reads from the dev file for the driver. + +The source code is located under kernel sources "drivers/staging/iio/Documentation/generic_buffer.c". + +How to compile: + +arm-arago-linux-gnueabi-gcc --static generic_buffer.c -o generic_buffer + +or + +-gcc --static generic_buffer.c -o generic_buffer + + +SOURCE: https://github.com/ZubairLK/adc-iio-continuous-sampling-userspace \ No newline at end of file diff --git a/sensors/sensors test drivers (c)/script_adc.sh b/sensors/sensors test drivers (c)/script_adc.sh new file mode 100644 index 0000000..2afcb63 --- /dev/null +++ b/sensors/sensors test drivers (c)/script_adc.sh @@ -0,0 +1,5 @@ +echo 1 > /sys/bus/iio/devices/iio_sysfs_trigger/add_trigger +echo 1 > /sys/bus/iio/devices/iio\:device0/scan_elements/in_voltage7_en +echo 1 > /sys/bus/iio/devices/iio\:device0/scan_elements/in_voltage5_en +generic_buffer -n TI-am335x-adc -t sysfstrig1 -l 128 + diff --git a/sensors/sensors test drivers (c)/script_trigger.sh b/sensors/sensors test drivers (c)/script_trigger.sh new file mode 100644 index 0000000..cdaf2d1 --- /dev/null +++ b/sensors/sensors test drivers (c)/script_trigger.sh @@ -0,0 +1 @@ +echo 1 > /sys/bus/iio/devices/trigger0/trigger_now diff --git a/sensors/simple code examples.c b/sensors/simple code examples.c new file mode 100644 index 0000000..0a973ba --- /dev/null +++ b/sensors/simple code examples.c @@ -0,0 +1,54 @@ +//Code to blink an LED - just to illustrate that it's pretty easy +//Only important thing is which name to address the LED by + +#include +#include + +using namespace std; + +int main(int argc, char** argv) { + FILE *LEDHandle = NULL; + char *LEDBrightness = "/sys/class/leds/beaglebone:green:usr0/brightness"; + printf("\nStarting LED blink program wooo!\n"); + while(1){ + if((LEDHandle = fopen(LEDBrightness, "r+")) != NULL){ + fwrite("1", sizeof(char), 1, LEDHandle); + fclose(LEDHandle); + } + sleep(1); + if((LEDHandle = fopen(LEDBrightness, "r+")) != NULL){ + fwrite("0", sizeof(char), 1, LEDHandle); + fclose(LEDHandle); + } + sleep(1); + } + return 0; +} + +//Sample code that should read a pressure sensor pin (conversion factors +//are just random numbers). Again pretty simple. + +#include STUFF + +double pressure(char *string) { + int value = atoi(string); + double millivolts = (value / 4096.0) * 1800; //convert input to volts + double pressure = (millivolts - 500.0) / 10.0; //convert volts to pressure + return pressure; +} + +void main() { + int fd = open("/sys/devices/platform/tsc/ain2", O_RDONLY); //open pin signal + while (1) { + char buffer[1024]; + int ret = read(fd, buffer, sizeof(buffer)); //get data + if (ret != -1) { + buffer[ret] = NULL; + double kpa = pressure(buffer); + printf("digital value: %s kilopascals: %f\n", buffer, kpa); + lseek(fd, 0, 0); + } + sleep(1); + } + close(fd); +} \ No newline at end of file diff --git a/sensors/simpleGPIO (c++)/SimpleGPIO.cpp b/sensors/simpleGPIO (c++)/SimpleGPIO.cpp new file mode 100644 index 0000000..ab17a98 --- /dev/null +++ b/sensors/simpleGPIO (c++)/SimpleGPIO.cpp @@ -0,0 +1,233 @@ +/* + * SimpleGPIO.cpp + * + * Modifications by Derek Molloy, School of Electronic Engineering, DCU + * www.eeng.dcu.ie/~molloyd/ + * Almost entirely based on Software by RidgeRun: + * + * Copyright (c) 2011, RidgeRun + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the RidgeRun. + * 4. Neither the name of the RidgeRun nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY RIDGERUN ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL RIDGERUN BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "SimpleGPIO.h" +#include +#include +#include +#include +#include +#include +#include + +/**************************************************************** + * gpio_export + ****************************************************************/ +int gpio_export(unsigned int gpio) +{ + int fd, len; + char buf[MAX_BUF]; + + fd = open(SYSFS_GPIO_DIR "/export", O_WRONLY); + if (fd < 0) { + perror("gpio/export"); + return fd; + } + + len = snprintf(buf, sizeof(buf), "%d", gpio); + write(fd, buf, len); + close(fd); + + return 0; +} + +/**************************************************************** + * gpio_unexport + ****************************************************************/ +int gpio_unexport(unsigned int gpio) +{ + int fd, len; + char buf[MAX_BUF]; + + fd = open(SYSFS_GPIO_DIR "/unexport", O_WRONLY); + if (fd < 0) { + perror("gpio/export"); + return fd; + } + + len = snprintf(buf, sizeof(buf), "%d", gpio); + write(fd, buf, len); + close(fd); + return 0; +} + +/**************************************************************** + * gpio_set_dir + ****************************************************************/ +int gpio_set_dir(unsigned int gpio, PIN_DIRECTION out_flag) +{ + int fd; + char buf[MAX_BUF]; + + snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/direction", gpio); + + fd = open(buf, O_WRONLY); + if (fd < 0) { + perror("gpio/direction"); + return fd; + } + + if (out_flag == OUTPUT_PIN) + write(fd, "out", 4); + else + write(fd, "in", 3); + + close(fd); + return 0; +} + +/**************************************************************** + * gpio_set_value + ****************************************************************/ +int gpio_set_value(unsigned int gpio, PIN_VALUE value) +{ + int fd; + char buf[MAX_BUF]; + + snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio); + + fd = open(buf, O_WRONLY); + if (fd < 0) { + perror("gpio/set-value"); + return fd; + } + + if (value==LOW) + write(fd, "0", 2); + else + write(fd, "1", 2); + + close(fd); + return 0; +} + +/**************************************************************** + * gpio_get_value + ****************************************************************/ +int gpio_get_value(unsigned int gpio, unsigned int *value) +{ + int fd; + char buf[MAX_BUF]; + char ch; + + snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio); + + fd = open(buf, O_RDONLY); + if (fd < 0) { + perror("gpio/get-value"); + return fd; + } + + read(fd, &ch, 1); + + if (ch != '0') { + *value = 1; + } else { + *value = 0; + } + + close(fd); + return 0; +} + + +/**************************************************************** + * gpio_set_edge + ****************************************************************/ + +int gpio_set_edge(unsigned int gpio, char *edge) +{ + int fd; + char buf[MAX_BUF]; + + snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/edge", gpio); + + fd = open(buf, O_WRONLY); + if (fd < 0) { + perror("gpio/set-edge"); + return fd; + } + + write(fd, edge, strlen(edge) + 1); + close(fd); + return 0; +} + +/**************************************************************** + * gpio_fd_open + ****************************************************************/ + +int gpio_fd_open(unsigned int gpio) +{ + int fd; + char buf[MAX_BUF]; + + snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio); + + fd = open(buf, O_RDONLY | O_NONBLOCK ); + if (fd < 0) { + perror("gpio/fd_open"); + } + return fd; +} + +/**************************************************************** + * gpio_fd_close + ****************************************************************/ + +int gpio_fd_close(int fd) +{ + return close(fd); +} + + +/**************************************************************** + * gpio_omap_mux_setup - Allow us to setup the omap mux mode for a pin + ****************************************************************/ +int gpio_omap_mux_setup(const char *omap_pin0_name, const char *mode) +{ + int fd; + char buf[MAX_BUF]; + snprintf(buf, sizeof(buf), SYSFS_OMAP_MUX_DIR "%s", omap_pin0_name); + fd = open(buf, O_WRONLY); + if (fd < 0) { + perror("failed to open OMAP_MUX"); + return fd; + } + write(fd, mode, strlen(mode) + 1); + close(fd); + return 0; +} \ No newline at end of file diff --git a/sensors/simpleGPIO (c++)/SimpleGPIO.h b/sensors/simpleGPIO (c++)/SimpleGPIO.h new file mode 100644 index 0000000..edbd78a --- /dev/null +++ b/sensors/simpleGPIO (c++)/SimpleGPIO.h @@ -0,0 +1,72 @@ +/* + * SimpleGPIO.h + * + * Copyright Derek Molloy, School of Electronic Engineering, Dublin City University + * www.eeng.dcu.ie/~molloyd/ + * + * Based on Software by RidgeRun + * Copyright (c) 2011, RidgeRun + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the RidgeRun. + * 4. Neither the name of the RidgeRun nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY RIDGERUN ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL RIDGERUN BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SIMPLEGPIO_H_ +#define SIMPLEGPIO_H_ + + /**************************************************************** + * Constants + ****************************************************************/ + +#define SYSFS_GPIO_DIR "/sys/class/gpio" +#define POLL_TIMEOUT (3 * 1000) /* 3 seconds */ +#define MAX_BUF 64 +#define SYSFS_OMAP_MUX_DIR "/sys/kernel/debug/omap_mux/" + +enum PIN_DIRECTION{ + INPUT_PIN=0, + OUTPUT_PIN=1 +}; + +enum PIN_VALUE{ + LOW=0, + HIGH=1 +}; + +/**************************************************************** + * gpio_export + ****************************************************************/ +int gpio_export(unsigned int gpio); +int gpio_unexport(unsigned int gpio); +int gpio_set_dir(unsigned int gpio, PIN_DIRECTION out_flag); +int gpio_set_value(unsigned int gpio, PIN_VALUE value); +int gpio_get_value(unsigned int gpio, unsigned int *value); +int gpio_set_edge(unsigned int gpio, char *edge); +int gpio_fd_open(unsigned int gpio); +int gpio_fd_close(int fd); +int gpio_omap_mux_setup(const char *omap_pin0_name, const char *mode); + +#endif /* SIMPLEGPIO_H_ */ \ No newline at end of file diff --git a/server/Makefile b/server/Makefile index f1084af..ef834a1 100644 --- a/server/Makefile +++ b/server/Makefile @@ -1,12 +1,13 @@ # Makefile for server software CXX = gcc FLAGS = -std=c99 -Wall -Werror -pedantic -g -LIB = -lpthread -lfcgi -lssl -OBJ = log.o sensor.o fastcgi.o main.o +LIB = -lpthread -lfcgi -lssl -lcrypto +OBJ = log.o sensor.o fastcgi.o thread.o main.o RM = rm -f BIN = server + $(BIN) : $(OBJ) $(CXX) $(FLAGS) -o $(BIN) $(OBJ) $(LIB) diff --git a/server/common.h b/server/common.h index 5f71f9f..9b73de9 100644 --- a/server/common.h +++ b/server/common.h @@ -17,8 +17,10 @@ #include #include #include +#include #include "log.h" #include "fastcgi.h" +#include "thread.h" #endif //_COMMON_H diff --git a/server/fastcgi.c b/server/fastcgi.c index 4fc3742..49bf197 100644 --- a/server/fastcgi.c +++ b/server/fastcgi.c @@ -11,9 +11,9 @@ #include #include "common.h" -#include "fastcgi.h" #include "sensor.h" #include "log.h" +#include "options.h" #define LOGIN_TIMEOUT 180 @@ -170,6 +170,16 @@ void FCGI_BeginJSON(FCGIContext *context, StatusCodes status_code) printf("{\r\n"); printf("\t\"module\" : \"%s\"", context->current_module); FCGI_JSONLong("status", status_code); + + // Jeremy: Should we include a timestamp in the JSON; something like this? + double start_time = g_options.start_time.tv_sec + 1e-6*(g_options.start_time.tv_usec); + struct timeval now; + gettimeofday(&now, NULL); + double current_time = now.tv_sec + 1e-6*(now.tv_usec); + FCGI_JSONDouble("start_time", start_time); + FCGI_JSONDouble("current_time", current_time); + FCGI_JSONDouble("running_time", current_time - start_time); + } /** @@ -203,6 +213,16 @@ void FCGI_JSONDouble(const char *key, double value) printf(",\r\n\t\"%s\" : %f", key, value); } +/** + * Similar to FCGI_JsonPair except for boolean values. + * @param key The key of the JSON entry + * @param value The value associated with the key + */ +void FCGI_JSONBool(const char *key, bool value) +{ + printf(",\r\n\t\"%s\" : %s", key, value ? "true" : "false"); +} + /** * Begins a JSON entry by writing the key. To be used in conjunction * with FCGI_JsonValue. @@ -248,7 +268,7 @@ void FCGI_RejectJSON(FCGIContext *context) FCGI_BeginJSON(context, STATUS_ERROR); FCGI_JSONPair("description", "Invalid request"); FCGI_JSONLong("responsenumber", context->response_number); - FCGI_JSONPair("params", getenv("DOCUMENT_URI_LOCAL")); + FCGI_JSONPair("params", getenv("QUERY_STRING")); FCGI_JSONPair("host", getenv("SERVER_HOSTNAME")); FCGI_JSONPair("user", getenv("REMOTE_USER")); FCGI_JSONPair("ip", getenv("REMOTE_ADDR")); @@ -258,12 +278,28 @@ void FCGI_RejectJSON(FCGIContext *context) /** * Main FCGI request loop that receives/responds to client requests. * @param data Reserved. + * @returns NULL (void* required for consistency with pthreads, although at the moment this runs in the main thread anyway) + * TODO: Get this to exit with the rest of the program! */ -void FCGI_RequestLoop (void *data) +void * FCGI_RequestLoop (void *data) { FCGIContext context = {0}; + Log(LOGDEBUG, "First request..."); + //TODO: The FCGI_Accept here is blocking. + // That means that if another thread terminates the program, this thread + // will not terminate until the next request is made. while (FCGI_Accept() >= 0) { + + if (Thread_Runstate() != RUNNING) + { + //TODO: Yeah... deal with this better :P + Log(LOGERR, "FIXME; FCGI gets request after other threads have finished."); + printf("Content-type: text/plain\r\n\r\n+++OUT OF CHEESE ERROR+++\n"); + break; + } + + Log(LOGDEBUG, "Got request #%d", context.response_number); ModuleHandler module_handler = NULL; char module[BUFSIZ], params[BUFSIZ]; @@ -292,7 +328,15 @@ void FCGI_RequestLoop (void *data) strncat(module, " [unknown]", BUFSIZ); FCGI_RejectJSON(&context); } - context.response_number++; + + Log(LOGDEBUG, "Waiting for request #%d", context.response_number); } + + Log(LOGDEBUG, "Thread exiting."); + Thread_QuitProgram(false); + // NOTE: Don't call pthread_exit, because this runs in the main thread. Just return. + return NULL; + + } diff --git a/server/fastcgi.h b/server/fastcgi.h index e9db8ba..1efdef7 100644 --- a/server/fastcgi.h +++ b/server/fastcgi.h @@ -22,11 +22,12 @@ extern void FCGI_BeginJSON(FCGIContext *context, StatusCodes status_code); extern void FCGI_JSONPair(const char *key, const char *value); extern void FCGI_JSONLong(const char *key, long value); extern void FCGI_JSONDouble(const char *key, double value); +extern void FCGI_JSONBool(const char *key, bool value); extern void FCGI_JSONKey(const char *key); extern void FCGI_JSONValue(const char *format, ...); extern void FCGI_EndJSON(); extern void FCGI_RejectJSON(FCGIContext *context); -extern void FCGI_RequestLoop (void *data); +extern void * FCGI_RequestLoop (void *data); #endif diff --git a/server/log.c b/server/log.c index f7e39bc..7b67043 100644 --- a/server/log.c +++ b/server/log.c @@ -17,6 +17,9 @@ static const char * unspecified_funct = "???"; // --- Function implementations --- // +//TODO: Migrate to syslog (shouldn't be too hard; these functions basically do what syslog does) +// Note that we will want to have a seperate log as well as syslog; give the user the option to view the log using the GUI + /** * Print a message to stderr * @param level - Specify how severe the message is. diff --git a/server/main.c b/server/main.c index bfd5300..ec21a25 100644 --- a/server/main.c +++ b/server/main.c @@ -13,7 +13,6 @@ // --- Variable definitions --- // Options g_options; // options passed to program through command line arguments -Sensor g_sensors[NUMSENSORS]; // sensors array // --- Function definitions --- // @@ -26,6 +25,7 @@ void ParseArguments(int argc, char ** argv) { g_options.program = argv[0]; // program name g_options.verbosity = LOGDEBUG; // default log level + gettimeofday(&(g_options.start_time), NULL); // Start time Log(LOGDEBUG, "Called as %s with %d arguments.", g_options.program, argc); } @@ -35,12 +35,14 @@ void ParseArguments(int argc, char ** argv) */ //TODO: Something that gets massively annoying with threads is that you can't predict which one gets the signal // There are ways to deal with this, but I can't remember them +// Probably sufficient to just call Thread_QuitProgram here void SignalHandler(int signal) { // At the moment just always exit. // Call `exit` so that Cleanup will be called to... clean up. Log(LOGWARN, "Got signal %d (%s). Exiting.", signal, strsignal(signal)); - exit(signal); + Thread_QuitProgram(false); + //exit(signal); } /** @@ -58,20 +60,31 @@ void Cleanup() * @param argc - Num args * @param argv - Args * @returns 0 on success, error code on failure + * NOTE: NEVER USE exit(3)! Instead call Thread_QuitProgram */ int main(int argc, char ** argv) { ParseArguments(argc, argv); - // start sensor threads - for (int i = 0; i < NUMSENSORS; ++i) + // signal handler + //TODO: Make this work + /* + int signals[] = {SIGINT, SIGSEGV, SIGTERM}; + for (int i = 0; i < sizeof(signals)/sizeof(int); ++i) { - Sensor_Init(g_sensors+i, i); - pthread_create(&(g_sensors[i].thread), NULL, Sensor_Main, (void*)(g_sensors+i)); + signal(signals[i], SignalHandler); } + */ + Sensor_Spawn(); // run request thread in the main thread FCGI_RequestLoop(NULL); + + // Join the dark side, Luke + // *cough* + // Join the sensor threads + Sensor_Join(); + Cleanup(); return 0; } diff --git a/server/options.h b/server/options.h index 297acf4..a15e14a 100644 --- a/server/options.h +++ b/server/options.h @@ -14,6 +14,10 @@ typedef struct const char * program; /** Determines at what level log messages are shown **/ int verbosity; + /** Time at which program begins to run **/ + struct timeval start_time; + /** Time at which program exits **/ + struct timeval end_time; } Options; diff --git a/server/run.sh b/server/run.sh index 756f9cf..11f2e34 100755 --- a/server/run.sh +++ b/server/run.sh @@ -1,3 +1,5 @@ #!/bin/bash # Use this to quickly test run the server in valgrind -spawn-fcgi -p9005 -n /usr/bin/valgrind ./server +#spawn-fcgi -p9005 -n ./valgrind.sh +# Use this to run the server normally +spawn-fcgi -p9005 -n ./server diff --git a/server/sensor.c b/server/sensor.c index 6222510..34c9310 100644 --- a/server/sensor.c +++ b/server/sensor.c @@ -9,34 +9,44 @@ #include "sensor.h" #include +/** Array of sensors, initialised by Sensor_Init **/ +static Sensor g_sensors[NUMSENSORS]; //global to this file + /** * Read a data value from a sensor; block until value is read * @param sensor_id - The ID of the sensor - * @returns The current value of the sensor + * @param d - DataPoint to set + * @returns NULL on error, otherwise d */ -DataPoint GetData(int sensor_id) +DataPoint * GetData(int sensor_id, DataPoint * d) { // switch based on the sensor_id at the moment for testing; // might be able to just directly access ADC from sensor_id? //TODO: Implement for real sensors - DataPoint d; - //TODO: Deal with time stamps properly - static int count = 0; - d.time = count++; + + //TODO: We should ensure the time is *never* allowed to change on the server if we use gettimeofday + // Another way people might think of getting the time is to count CPU cycles with clock() + // But this will not work because a) CPU clock speed may change on some devices (RPi?) and b) It counts cycles used by all threads + gettimeofday(&(d->time_stamp), NULL); + switch (sensor_id) { case SENSOR_TEST0: - d.value = count; + { + static int count = 0; + d->value = count++; break; + } case SENSOR_TEST1: - d.value = (float)(rand() % 100) / 100; + d->value = (float)(rand() % 100) / 100; break; default: Fatal("Unknown sensor id: %d", sensor_id); break; } usleep(100000); // simulate delay in sensor polling + return d; } @@ -57,16 +67,15 @@ void Destroy(Sensor * s) * Initialise a sensor * @param s - Sensor to initialise */ -void Sensor_Init(Sensor * s, int id) +void Init(Sensor * s, int id) { s->write_index = 0; s->read_offset = 0; s->id = id; - #define FILENAMESIZE BUFSIZ + #define FILENAMESIZE 3 char filename[FILENAMESIZE]; - //if (s->id >= pow(10, FILENAMESIZE)) - if (false) + if (s->id >= pow(10, FILENAMESIZE)) { Fatal("Too many sensors! FILENAMESIZE is %d; increase it and recompile.", FILENAMESIZE); } @@ -81,6 +90,9 @@ void Sensor_Init(Sensor * s, int id) } + + + /** * Run the main sensor polling loop * @param arg - Cast to Sensor* - Sensor that the thread will handle @@ -90,7 +102,7 @@ void * Sensor_Main(void * arg) { Sensor * s = (Sensor*)(arg); - while (true) //TODO: Exit condition + while (Thread_Runstate() == RUNNING) //TODO: Exit condition { // The sensor will write data to a buffer until it is full // Then it will open a file and dump the buffer to the end of it. @@ -102,7 +114,11 @@ void * Sensor_Main(void * arg) while (s->write_index < SENSOR_DATABUFSIZ) { - s->buffer[s->write_index] = GetData(s->id); + DataPoint * d = &(s->buffer[s->write_index]); + if (GetData(s->id, d) == NULL) + { + Fatal("Error collecting data"); + } s->write_index += 1; } @@ -110,6 +126,8 @@ void * Sensor_Main(void * arg) // CRITICAL SECTION (no threads should be able to read/write the file at the same time) pthread_mutex_lock(&(s->mutex)); + //TODO: Valgrind complains about this fseek: "Syscall param write(buf) points to uninitialised byte(s)" + // Not sure why, but we should find out and fix it. fseek(s->file, 0, SEEK_END); int amount_written = fwrite(s->buffer, sizeof(DataPoint), SENSOR_DATABUFSIZ, s->file); if (amount_written != SENSOR_DATABUFSIZ) @@ -123,7 +141,8 @@ void * Sensor_Main(void * arg) s->write_index = 0; // reset position in buffer } - return NULL; + Log(LOGDEBUG, "Thread for sensor %d exits", s->id); + return NULL; } /** @@ -146,6 +165,27 @@ int Sensor_Query(Sensor * s, DataPoint * buffer, int bufsiz) return amount_read; } +/** + * Get a Sensor given an ID string + * @param id_str ID string + * @returns Sensor* identified by the string; NULL on error + */ +Sensor * Sensor_Identify(const char * id_str) +{ + char * end; + // Parse string as integer + int id = strtol(id_str, &end, 10); + if (*end != '\0') + { + return NULL; + } + // Bounds check + if (id < 0 || id > NUMSENSORS) + return NULL; + + return g_sensors+id; +} + /** * Handle a request to the sensor module * @param context - The context to work in @@ -157,15 +197,14 @@ void Sensor_Handler(FCGIContext *context, char * params) StatusCodes status = STATUS_OK; const char * key; const char * value; - int sensor_id = SENSOR_NONE; + Sensor * sensor = NULL; while ((params = FCGI_KeyPair(params, &key, &value)) != NULL) { Log(LOGDEBUG, "Got key=%s and value=%s", key, value); if (strcmp(key, "id") == 0) { - char *end; - if (sensor_id != SENSOR_NONE) + if (sensor != NULL) { Log(LOGERR, "Only one sensor id should be specified"); status = STATUS_ERROR; @@ -177,11 +216,11 @@ void Sensor_Handler(FCGIContext *context, char * params) status = STATUS_ERROR; break; } - //TODO: Use human readable sensor identifier string for API? - sensor_id = strtol(value, &end, 10); - if (*end != '\0') + + sensor = Sensor_Identify(value); + if (sensor == NULL) { - Log(LOGERR, "Sensor id not an integer; %s", value); + Log(LOGERR, "Invalid sensor id: %s", value); status = STATUS_ERROR; break; } @@ -194,14 +233,9 @@ void Sensor_Handler(FCGIContext *context, char * params) } } - if (sensor_id == SENSOR_NONE) - { - Log(LOGERR, "No sensor id specified"); - status = STATUS_ERROR; - } - else if (sensor_id >= NUMSENSORS || sensor_id < 0) + if (status != STATUS_ERROR && sensor == NULL) { - Log(LOGERR, "Invalid sensor id %d", sensor_id); + Log(LOGERR, "No valid sensor id given"); status = STATUS_ERROR; } @@ -211,17 +245,21 @@ void Sensor_Handler(FCGIContext *context, char * params) } else { + FCGI_BeginJSON(context, status); FCGI_JSONPair(key, value); // should spit back sensor ID //Log(LOGDEBUG, "Call Sensor_Query..."); - int amount_read = Sensor_Query(&(g_sensors[sensor_id]), buffer, SENSOR_QUERYBUFSIZ); + int amount_read = Sensor_Query(sensor, buffer, SENSOR_QUERYBUFSIZ); //Log(LOGDEBUG, "Read %d DataPoints", amount_read); //Log(LOGDEBUG, "Produce JSON response"); FCGI_JSONKey("data"); FCGI_JSONValue("["); for (int i = 0; i < amount_read; ++i) { - FCGI_JSONValue("[%f, %f]", buffer[i].time, buffer[i].value); + //TODO: Consider; is it better to give both tv_sec and tv_usec to the client seperately, instead of combining here? + //NOTE: Must always use doubles; floats get rounded! + double time = buffer[i].time_stamp.tv_sec + 1e-6*(buffer[i].time_stamp.tv_usec); + FCGI_JSONValue("[%f, %f]", time, buffer[i].value); if (i+1 < amount_read) FCGI_JSONValue(","); } @@ -230,3 +268,32 @@ void Sensor_Handler(FCGIContext *context, char * params) FCGI_EndJSON(); } } + +/** + * Setup Sensors, start Sensor polling thread(s) + */ +void Sensor_Spawn() +{ + // start sensor threads + for (int i = 0; i < NUMSENSORS; ++i) + { + Init(g_sensors+i, i); + pthread_create(&(g_sensors[i].thread), NULL, Sensor_Main, (void*)(g_sensors+i)); + } +} + +/** + * Quit Sensor loops + */ +void Sensor_Join() +{ + if (!Thread_Runstate()) + { + Fatal("This function should not be called before Thread_QuitProgram"); + } + for (int i = 0; i < NUMSENSORS; ++i) + { + pthread_join(g_sensors[i].thread, NULL); + Destroy(g_sensors+i); + } +} diff --git a/server/sensor.h b/server/sensor.h index 4009e5a..a259036 100644 --- a/server/sensor.h +++ b/server/sensor.h @@ -20,7 +20,7 @@ typedef struct { /** Time at which data was taken **/ - float time; + struct timeval time_stamp; //TODO: Consider; use float instead? /** Value of data **/ float value; } DataPoint; @@ -29,7 +29,7 @@ typedef struct typedef struct { /** ID number of the sensor **/ - enum {SENSOR_TEST0=0, SENSOR_TEST1=1, SENSOR_NONE} id; + enum {SENSOR_TEST0=0, SENSOR_TEST1=1} id; /** Buffer to store data from the sensor **/ DataPoint buffer[SENSOR_DATABUFSIZ]; /** Index of last point written in the data buffer **/ @@ -46,10 +46,10 @@ typedef struct } Sensor; -/** Array of Sensors **/ -extern Sensor g_sensors[]; -extern void Sensor_Init(Sensor * s, int id); // Initialise sensor + +extern void Sensor_Spawn(); // Initialise sensor +extern void Sensor_Join(); //Join sensor threads extern void * Sensor_Main(void * args); // main loop for sensor thread; pass a Sensor* cast to void* extern int Sensor_Query(Sensor * s, DataPoint * buffer, int bufsiz); // fill buffer with sensor data diff --git a/server/thread.c b/server/thread.c new file mode 100644 index 0000000..57473ea --- /dev/null +++ b/server/thread.c @@ -0,0 +1,62 @@ +/** + * @file thread.c + * @purpose Implementation of thread control + */ + +#include "thread.h" +#include "options.h" + +pthread_mutex_t mutex_runstate = PTHREAD_MUTEX_INITIALIZER; +Runstate runstate = RUNNING; + +/** + * Set the runstate, causing all threads to exit when they next check Thread_Runstate + * Repeated calls to this function have no effect on the runstate. + * @param error - Set to true to indicate an error occured + */ +void Thread_QuitProgram(bool error) +{ + if (runstate != RUNNING) + { + Log(LOGNOTE, "Called when program is not running; runstate = %d", runstate); + return; + } + + + Log(LOGNOTE, "Program will quit; error = %d", (int)error); + + //CRITICAL SECTION - We do NOT want multiple threads editing the runstate at the same time! + pthread_mutex_lock(&mutex_runstate); + if (error) + runstate = QUIT_ERROR; + else + runstate = QUIT; + + gettimeofday(&g_options.end_time, NULL); + pthread_mutex_unlock(&mutex_runstate); + // End critical section +} + +/** + * Check the runstate; to be called periodically by all threads. + * This function will call Thread_QuitProgram and change the Runstate there is an exit condition detected. + */ +Runstate Thread_Runstate() +{ + //TODO: Add real exit conditions; for testing purposes, set a timeout + /* + struct timeval time; + gettimeofday(&time, NULL); + Log(LOGDEBUG, "It has been %d seconds since program started.", time.tv_sec - g_options.start_time.tv_sec); + if (time.tv_sec - g_options.start_time.tv_sec > 3) + { + Thread_QuitProgram(false); + } + */ + + // Just reading the runstate doesn't really require a mutex + // The worst case: Another thread alters the runstate before this thread gets the result; this thread thinks the program is still running + // In that case, the thread will run an extra cycle of its loop and *then* exit. Since the runstate can only be changed once. + // We could put a mutex here anyway, but it will have an impact on how fast the loops can run. + return runstate; +} diff --git a/server/thread.h b/server/thread.h new file mode 100644 index 0000000..14ae785 --- /dev/null +++ b/server/thread.h @@ -0,0 +1,21 @@ +/** + * @file thread.h + * @purpose Declarations for thread control related functions and variables + */ + +#ifndef _THREAD_H +#define _THREAD_H + +#include "common.h" +#include + +typedef enum {QUIT, QUIT_ERROR, RUNNING} Runstate; + +/** Determine if the thread should exit; to be called periodically **/ +extern Runstate Thread_Runstate(); +/** Tell all other threads (when they call Thread_ExitCondition) to exit. Repeated calls have no effect. **/ +extern void Thread_QuitProgram(bool error); + +#endif //_THREAD_H + +//EOF diff --git a/server/valgrind.sh b/server/valgrind.sh new file mode 100755 index 0000000..2a50865 --- /dev/null +++ b/server/valgrind.sh @@ -0,0 +1,2 @@ +#!/bin/bash +valgrind --leak-check=full ./server diff --git a/testing/fastcgi-approach/-etc-nginx/fastcgi_params b/testing/fastcgi-approach/-etc-nginx/fastcgi_params deleted file mode 100644 index 51aa692..0000000 --- a/testing/fastcgi-approach/-etc-nginx/fastcgi_params +++ /dev/null @@ -1,27 +0,0 @@ -fastcgi_param QUERY_STRING $query_string; -fastcgi_param REQUEST_METHOD $request_method; -fastcgi_param CONTENT_TYPE $content_type; -fastcgi_param CONTENT_LENGTH $content_length; - -fastcgi_param SCRIPT_FILENAME $request_filename; -fastcgi_param SCRIPT_NAME $fastcgi_script_name; -fastcgi_param REQUEST_URI $request_uri; -fastcgi_param DOCUMENT_URI $document_uri; -fastcgi_param DOCUMENT_ROOT $document_root; -fastcgi_param SERVER_PROTOCOL $server_protocol; - -fastcgi_param GATEWAY_INTERFACE CGI/1.1; -fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; -fastcgi_param SERVER_HOSTNAME mctxsoft; - -fastcgi_param REMOTE_ADDR $remote_addr; -fastcgi_param REMOTE_PORT $remote_port; -fastcgi_param REMOTE_USER $remote_user; -fastcgi_param SERVER_ADDR $server_addr; -fastcgi_param SERVER_PORT $server_port; -fastcgi_param SERVER_NAME $server_name; - -fastcgi_param HTTPS $https; - -# PHP only, required if PHP was built with --enable-force-cgi-redirect -fastcgi_param REDIRECT_STATUS 200; diff --git a/testing/fastcgi-approach/-etc-nginx/sites-enabled/default b/testing/fastcgi-approach/-etc-nginx/sites-enabled/default deleted file mode 100644 index 541f6d1..0000000 --- a/testing/fastcgi-approach/-etc-nginx/sites-enabled/default +++ /dev/null @@ -1,131 +0,0 @@ -# You may add here your -# server { -# ... -# } -# statements for each of your virtual hosts to this file - -## -# You should look at the following URL's in order to grasp a solid understanding -# of Nginx configuration files in order to fully unleash the power of Nginx. -# http://wiki.nginx.org/Pitfalls -# http://wiki.nginx.org/QuickStart -# http://wiki.nginx.org/Configuration -# -# Generally, you will want to move this file somewhere, and start with a clean -# file but keep this around for reference. Or just disable in sites-enabled. -# -# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples. -## - -server { - listen 80; - listen [::]:80 default_server ipv6only=on; - - root /usr/share/nginx/html; - index index.php index.html index.htm; - - # Make site accessible from http://localhost/ - server_name localhost; - - location / { - # First attempt to serve request as file, then - # as directory, then fall back to displaying a 404. - try_files $uri $uri/ =404; - # Uncomment to enable naxsi on this location - # include /etc/nginx/naxsi.rules - } - - # Only for nginx-naxsi used with nginx-naxsi-ui : process denied requests - #location /RequestDenied { - # proxy_pass http://127.0.0.1:8080; - #} - - #error_page 404 /404.html; - - # redirect server error pages to the static page /50x.html - # - #error_page 500 502 503 504 /50x.html; - #location = /50x.html { - # root /usr/share/nginx/html; - #} - - # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 - # - location ~ \.php$ { - fastcgi_split_path_info ^(.+\.php)(/.+)$; - # # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini - # - # # With php5-cgi alone: - # fastcgi_pass 127.0.0.1:9000; - # # With php5-fpm: - fastcgi_pass unix:/var/run/php5-fpm.sock; - fastcgi_index index.php; - include fastcgi_params; - } - - # deny access to .htaccess files, if Apache's document root - # concurs with nginx's one - # - location ~ /\.ht { - deny all; - } - - #Login area - location ^~ /api/login { - auth_basic "Restricted Access"; - auth_basic_user_file /usr/share/nginx/access/.htpasswd; - - fastcgi_pass 127.0.0.1:9005; - fastcgi_param DOCUMENT_URI_LOCAL login; - include fastcgi_params; - } - - #MCTX API - location /api { - location ~ ^/api/?([^?]*) { - fastcgi_pass 127.0.0.1:9005; - fastcgi_param DOCUMENT_URI_LOCAL $1; - include fastcgi_params; - } - } -} - - -# another virtual host using mix of IP-, name-, and port-based configuration -# -#server { -# listen 8000; -# listen somename:8080; -# server_name somename alias another.alias; -# root html; -# index index.html index.htm; -# -# location / { -# try_files $uri $uri/ =404; -# } -#} - - -# HTTPS server -# -#server { -# listen 443; -# server_name localhost; -# -# root html; -# index index.html index.htm; -# -# ssl on; -# ssl_certificate cert.pem; -# ssl_certificate_key cert.key; -# -# ssl_session_timeout 5m; -# -# ssl_protocols SSLv3 TLSv1; -# ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv3:+EXP; -# ssl_prefer_server_ciphers on; -# -# location / { -# try_files $uri $uri/ =404; -# } -#}