LyogIEVOQ09ERVIgT1BFUkFURUQgQ09NQklOQVRJT04gTE9DSyBWIDMuMgoKICAgICBDb3B5cmlnaHQgMjAxOSBieSBEb3VnIFBpcmtleQoKICAgIFRoaXMgd29yayBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQ3JlYXRpdmUgQ29tbW9ucyBBdHRyaWJ1dGlvbiA0LjAgSW50ZXJuYXRpb25hbCBMaWNlbnNlLgogICAgVG8gdmlldyBhIGNvcHkgb2YgdGhpcyBsaWNlbnNlLCB2aXNpdCBodHRwOi8vYy4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4ucy5vcmcvbGljZW5zZXMvYnkvNC4wLy4KCgogICAgIEEgc2ltdWxhdGlvbiBvZiBhIG1lY2hhbmljYWwgZGlhbCBjb21iaW5hdGlvbiBsb2NrIHRvIHJ1biBvbiBhbiBBcmR1aW5vIFVOTwoKICAgICBQcm9ncmFtIERlbW9uc3RyYXRlczoKICAgICAgIEVFUFJPTSBzYXZlL3Jlc3RvcmUKICAgICAgIFBpbiBjaGFuZ2UgaW50ZXJydXB0cwogICAgICAgU2xlZXAgbW9kZQogICAgICAgU2VsZi1tYWRlIHRpbWVyIGxpYnJhcnkKICAgICAgIG1lbXNldCgpLCBtZW1jbXAoKSwgbWVtY3B5KCkKICAgICAgIFJvdGFyeSBlbmNvZGVyIHcgZXh0ZXJuYWwgaW50ZXJydXB0cwogICAgICAgI2RlZmluZXMgZm9yIGNvbXBpbGUgdGltZSBvcHRpb25zCiAgICAgICBTd2l0Y2gvY2FzZSBzdGF0ZSBtYWNoaW5lCgogICAgIE51bWJlciBvZiBwb3NzaWJsZSBjb21iaW5hdGlvbnMgaXMgZ2l2ZW4gYnkgbl5yOgogICAgIG4gPSBudW1iZXIgb2YgZGlmZmVyZW50IG51bWJlcnMgKDQwKQogICAgIHIgPSBudW1iZXIgb2YgdHVtYmxlcnMgdXNlZCAoNSkKCiAgICAgU28gdGhlIGN1cnJlbnQgY29uZmlndXJhdGlvbiB5aWVsZHMgMTAyLDQwMCwwMDAgcG9zc2libGUgY29tYmluYXRpb25zLAogICAgIGNvcnJlY3RseSBjYWxsZWQgcGVybXV0YXRpb25zLgoKICAgICBOdW1iZXIgbG9jayBwZXJtdXRhdGlvbnMgY2FsY3VsYXRvcgogICAgIGh0dHBzOi8vdy4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4ubi5jb20vc3RhdGlzdGljcy9udW1iZXItbG9jay1wZXJtdXRhdGlvbnMucGhwCiovCi8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KLy8gICAgRUVQUk9NLmggaXMgcGFydCBvZiB0aGUgQXJkdWlubyBsaWJyYXJ5LgoKLy8gaHR0cHM6Ly93Li4uY29udGVudC1hdmFpbGFibGUtdG8tYXV0aG9yLW9ubHkuLi5vLmNjL2VuL1JlZmVyZW5jZS9FRVBST00vCgovLyBodHRwczovL2MuLi5jb250ZW50LWF2YWlsYWJsZS10by1hdXRob3Itb25seS4uLnMub3JnL2xpY2Vuc2VzL2J5LXNhLzMuMC8KCiNpbmNsdWRlICZsdDtFRVBST00uaCZndDsgIC8vIEZvciBzdG9yYWdlL3JldHJpZXZhbCBvZiBsb2NrIGNvZGUKCi8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KLy8gICBDaGFuZ2UgdGhlc2UgdHdvIG51bWJlcnMgdG8gdGhlIHBpbnMgY29ubmVjdGVkIHRvIHlvdXIgZW5jb2Rlci4KLy8gICBCZXN0IFBlcmZvcm1hbmNlOiBib3RoIHBpbnMgaGF2ZSBpbnRlcnJ1cHQgY2FwYWJpbGl0eQovLyAgIEdvb2QgUGVyZm9ybWFuY2U6IG9ubHkgdGhlIGZpcnN0IHBpbiBoYXMgaW50ZXJydXB0IGNhcGFiaWxpdHkKLy8gICBMb3cgUGVyZm9ybWFuY2U6ICBuZWl0aGVyIHBpbiBoYXMgaW50ZXJydXB0IGNhcGFiaWxpdHkKLy8gICBSZWZlciB0byB0aGUgbGluayBmb3IgdGhlIHJvdGFyeSBlbmNvZGVyIGxpY2Vuc2UKCi8vIFBhdWxTdG9mZnJlZ2VuJ3MgR2l0SHViIHBhZ2UgZm9yIHRoZSBlbmNvZGVyIGxpYnJhcnkgLSBodHRwczovL2cuLi5jb250ZW50LWF2YWlsYWJsZS10by1hdXRob3Itb25seS4uLmIuY29tL1BhdWxTdG9mZnJlZ2VuL0VuY29kZXIKLy8gbGljZW5zZSBkZXNjcmlwdGlvbiAtIGh0dHBzOi8vZy4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4uYi5jb20vUGF1bFN0b2ZmcmVnZW4vRW5jb2Rlci9ibG9iL21hc3Rlci9FbmNvZGVyLmgKI2luY2x1ZGUgJmx0O0VuY29kZXIuaCZndDsKRW5jb2RlciBDb21ib0RpYWwoMiwgMyk7CgovLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKI2luY2x1ZGUgJnF1b3Q7TXVsdGlfVGltZXIuaCZxdW90OyAvLyBzZWxmLW1hZGUgdGltZXIgbGlicmFyeQoKLy8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgovKiBTbGVlcCBsaWJyYXJ5IGlzIGNvcHlyaWdodCBNaWNyb2NoaXAuCgogIGh0dHBzOi8vdy4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4udS5vcmcvYXZyLWxpYmMvdXNlci1tYW51YWwvc2xlZXBfOGhfc291cmNlLmh0bWwuCgogICBDb3B5cmlnaHQgKGMpIDIwMDIsIDIwMDQgVGhlb2RvcmUgQS4gUm90aAogICBDb3B5cmlnaHQgKGMpIDIwMDQsIDIwMDcsIDIwMDggRXJpYyBCLiBXZWRkaW5ndG9uCiAgIENvcHlyaWdodCAoYykgMjAwNSwgMjAwNiwgMjAwNyBKb2VyZyBXdW5zY2gKICAgQWxsIHJpZ2h0cyByZXNlcnZlZC4KCiAgIFJlZGlzdHJpYnV0aW9uIGFuZCB1c2UgaW4gc291cmNlIGFuZCBiaW5hcnkgZm9ybXMsIHdpdGggb3Igd2l0aG91dAogICBtb2RpZmljYXRpb24sIGFyZSBwZXJtaXR0ZWQgcHJvdmlkZWQgdGhhdCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnMgYXJlIG1ldDoKCiAgICAgUmVkaXN0cmlidXRpb25zIG9mIHNvdXJjZSBjb2RlIG11c3QgcmV0YWluIHRoZSBhYm92ZSBjb3B5cmlnaHQKICAgICBub3RpY2UsIHRoaXMgbGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2NsYWltZXIuCgogICAgIFJlZGlzdHJpYnV0aW9ucyBpbiBiaW5hcnkgZm9ybSBtdXN0IHJlcHJvZHVjZSB0aGUgYWJvdmUgY29weXJpZ2h0CiAgICAgbm90aWNlLCB0aGlzIGxpc3Qgb2YgY29uZGl0aW9ucyBhbmQgdGhlIGZvbGxvd2luZyBkaXNjbGFpbWVyIGluCiAgICAgdGhlIGRvY3VtZW50YXRpb24gYW5kL29yIG90aGVyIG1hdGVyaWFscyBwcm92aWRlZCB3aXRoIHRoZQogICAgIGRpc3RyaWJ1dGlvbi4KCiAgICAgTmVpdGhlciB0aGUgbmFtZSBvZiB0aGUgY29weXJpZ2h0IGhvbGRlcnMgbm9yIHRoZSBuYW1lcyBvZgogICAgIGNvbnRyaWJ1dG9ycyBtYXkgYmUgdXNlZCB0byBlbmRvcnNlIG9yIHByb21vdGUgcHJvZHVjdHMgZGVyaXZlZAogICAgIGZyb20gdGhpcyBzb2Z0d2FyZSB3aXRob3V0IHNwZWNpZmljIHByaW9yIHdyaXR0ZW4gcGVybWlzc2lvbi4KCiAgIFRISVMgU09GVFdBUkUgSVMgUFJPVklERUQgQlkgVEhFIENPUFlSSUdIVCBIT0xERVJTIEFORCBDT05UUklCVVRPUlMgJnF1b3Q7QVMgSVMmcXVvdDsKICAgQU5EIEFOWSBFWFBSRVNTIE9SIElNUExJRUQgV0FSUkFOVElFUywgSU5DTFVESU5HLCBCVVQgTk9UIExJTUlURUQgVE8sIFRIRQogICBJTVBMSUVEIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZIEFORCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRQogICBBUkUgRElTQ0xBSU1FRC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFIENPUFlSSUdIVCBPV05FUiBPUiBDT05UUklCVVRPUlMgQkUKICAgTElBQkxFIEZPUiBBTlkgRElSRUNULCBJTkRJUkVDVCwgSU5DSURFTlRBTCwgU1BFQ0lBTCwgRVhFTVBMQVJZLCBPUgogICBDT05TRVFVRU5USUFMIERBTUFHRVMgKElOQ0xVRElORywgQlVUIE5PVCBMSU1JVEVEIFRPLCBQUk9DVVJFTUVOVCBPRgogICBTVUJTVElUVVRFIEdPT0RTIE9SIFNFUlZJQ0VTOyBMT1NTIE9GIFVTRSwgREFUQSwgT1IgUFJPRklUUzsgT1IgQlVTSU5FU1MKICAgSU5URVJSVVBUSU9OKSBIT1dFVkVSIENBVVNFRCBBTkQgT04gQU5ZIFRIRU9SWSBPRiBMSUFCSUxJVFksIFdIRVRIRVIgSU4KICAgQ09OVFJBQ1QsIFNUUklDVCBMSUFCSUxJVFksIE9SIFRPUlQgKElOQ0xVRElORyBORUdMSUdFTkNFIE9SIE9USEVSV0lTRSkKICAgQVJJU0lORyBJTiBBTlkgV0FZIE9VVCBPRiBUSEUgVVNFIE9GIFRISVMgU09GVFdBUkUsIEVWRU4gSUYgQURWSVNFRCBPRiBUSEUKICAgUE9TU0lCSUxJVFkgT0YgU1VDSCBEQU1BR0UuCiovCiNpbmNsdWRlICZsdDthdnIvc2xlZXAuaCZndDsKLy8KLy8gKioqKiAgRGVmaW5lcyB0byBjb250cm9sIHJ1bnRpbWUgZmVhdHVyZXMgICoqKioKLy8KI2RlZmluZSBQT1dFUl9TQVZFICAvLyBlbmFibGVzIHByb2Nlc3NvciBwb3dlciBkb3duIGZlYXR1cmUKLy8KI2RlZmluZSBWRVJJRllfTkVXX0NPTUJPICAvLyBlbmFibGVzIG5ldyBjb21ibyB2ZXJpZmljYXRpb24gY29kZSBpbiBzdGF0ZSBtYWNoaW5lCi8vCiNkZWZpbmUgRElTUExBWV9MT0NLX0NPREUgIC8vIHByaW50IHN0b3JlZCBjb2RlIGFuZCBlbnRlcmVkIGNvZGUgb24gc2VyaWFsIG1vbml0b3IKLy8KLy8gPT09PT09PT09PT09PT09PSAgQ29uc3RhbnRzICA9PT09PT09PT09PT09PQoKY29uc3QgdWludDhfdCBJTlRQSU4xID0gMjsgICAgICAgIC8vIFJvdGFyeSBlbmNvZGVyIGludGVycnVwdCBvbiB0aGlzIEFyZHVpbm8gVW5vIHBpbi4KY29uc3QgdWludDhfdCBJTlRQSU4yID0gMzsgICAgICAgIC8vIFJvdGFyeSBlbmNvZGVyIGludGVycnVwdCBvbiB0aGlzIEFyZHVpbm8gVW5vIHBpbi4KY29uc3QgdWludDhfdCBFTkNPREVSX1BCID0gNTsgICAgIC8vIEVuY29kZXIgcHVzaGJ1dHRvbiBpbnB1dApjb25zdCB1aW50OF90IGxvY2tTb2xlbm9pZCA9IDc7ICAgICAgLy8gKzUtLS9cL1wvLSAzMzAmT21lZ2E7IC0tJmd0O3wtLURJTzcKY29uc3QgdWludDhfdCBTRVRfVE9fREVGQVVMVCA9IDg7ICAgIC8vIFBpbiBoZWxkIGxvdyBhdCBwb3dlci11cCByZXNldHMgdG8gZGVmYXVsdCBjb21ibyAtIDIyMQpjb25zdCB1aW50OF90IG1vZGVMRUQgPSA5OyAgICAgICAgICAgLy8gKzUtLS9cL1wvLSAzMzAmT21lZ2E7IC0tJmd0O3wtLURJTzkKY29uc3QgdWludDhfdCBkZXRlbnRGbGFzaExFRCA9IDEyOyAgIC8vICs1LS0vXC9cLy0gMzMwJk9tZWdhOyAtLSZndDt8LS1ESTEyCgpjb25zdCB1aW50OF90IE1BWF9UVU1CTEVSUyA9IDU7ICAgICAgLy8gbnVtYmVyIG9mIHBvc3NpYmxlIGNvZGUgZW50cmllcwpjb25zdCB1aW50OF90IE1BWF9UVU1CTEVSX0NPREUgPSA0MDsgLy8gbWF4IG51bWJlciBvZiBkaWFsIHR1cm5zIHBlciBjb2RlIGVudHJ5Lgpjb25zdCB1bnNpZ25lZCBpbnQgRUVQUk9NX0JBU0UgPSAyMDsgLy8gc3RhcnRpbmcgRUVQUk9NIGFkZHJlc3MgZm9yIGNvZGUgc3RvcmFnZQoKY29uc3QgYm9vbCBDVyA9IHRydWU7ICAgICAgICAgICAgICAgIC8vIEVuY29kZXIgZGlyZWN0aW9uCmNvbnN0IGJvb2wgQ0NXID0gIUNXOyAgICAgICAgICAgICAgICAvLyBib29sZWFucwoKY29uc3QgYm9vbCBQQl9QVUxTRSA9IHRydWU7ICAgICAvLyByZWFkRW5jb2RlclBCIGFyZ3VtZW50CmNvbnN0IGJvb2wgUEJfU1RBVEUgPSAgZmFsc2U7ICAgLy8gcmVhZEVuY29kZXJQQiBhcmd1bWVudAoKLy8gPT09PT09PT09PT09PT09PT0gIFZhcmlhYmxlcyAgPT09PT09PT09PT09PT09PT09PT0KCnVpbnQ4X3QgdHVtYmxlckRhdGFbTUFYX1RVTUJMRVJTXTsgIC8vIGhvbGRzIG51bWJlcnMgZW50ZXJlZCBmb3Igb3BlbmluZyBvciBjb21ibyBzZXR0aW5nCnVpbnQ4X3QgbG9ja0NvZGVbXSB7MiwgMiwgMSwgMCwgMH07IC8vIGhvbGRzIHdvcmtpbmcgY29tYmluYXRpb24gdG8gb3BlbiBsb2NrLgovLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAyMjEgaXMgZGVmYXVsdCBmb3IgcmVzZXQvdHJvdWJsZXNob290aW5nCnVpbnQ4X3QgbmV3Q29kZVtNQVhfVFVNQkxFUlNdOyAvLyB0ZW1wIHN0b3JhZ2Ugb2YgY2hhbmdlZCBjb2RlCmludDhfdCB3b3JraW5nVHVtYmxlciA9IC0xOyAgIC8vIHdoaWNoIGNvZGUgbnVtYmVyIGlzIGJlaW5nIGVudGVyZWQKYm9vbCBpc0VuY29kZXJEaXJlY3Rpb25DVzsgICAgLy8gY2xvY2t3aXNlL2NvdW50ZXJjbG9ja3dpc2UgaW5kaWNhdG9yCmJvb2wgaXNFbmNvZGVyUEJQcmVzc2VkOwpib29sIHRlbGx0YWxlID0gZmFsc2U7ICAgIC8vIGRlYnVnZ2luZyBhaWQKYm9vbCBpc0NoYW5nZUNvbWJvRmxhZzsKYm9vbCBjb2RlRXJyb3I7IC8vIFRvbyBtYW55IG51bWJlcnMgZW50ZXJlZAoKdW5zaWduZWQgbG9uZyBsYXN0RGVib3VuY2VUaW1lID0gMDsgIC8vIHRoZSBsYXN0IHRpbWUgdGhlIG91dHB1dCBwaW4gd2FzIHRvZ2dsZWQKdW5zaWduZWQgbG9uZyBkZWJvdW5jZURlbGF5ID0gNTA7ICAgIC8vIHRoZSBkZWJvdW5jZSB0aW1lOyBpbmNyZWFzZSBpZiB0aGUgb3V0cHV0IGZsaWNrZXJzCgpib29sIGVuY29kZXJUdXJuZWQ7ICAvLyAgU2lnbmFscyBlbmNvZGVyIGFjdGl2aXR5CgovLyA9PT09PT09PT09PT09ICBEZWZpbmUgc3RhdGUgbWFjaGluZSBuYW1lcyAgPT09PT09PT09PT09CmVudW0gOiBieXRlIHsKICBGSVJTVF9TQ0FOLAogIElOSVRfRU5URVIsCiAgRU5URVJfQ09NQk8sCiAgSU5JVF9PUEVOLAogIE9QRU5fTE9DSywKICBJTklUX05FVywKICBORVdfQ09NQk8sCiAgSU5JVF9WRVJJRlksCiAgVkVSSUZZX0NPTUJPLAp9IGxvY2tTdGF0ZTsKCi8vIFRpbWVycyAtIGZyb20gTXVsdGlfdGltZXIuaApPbkRlbGF5X3RtciBkZXRlbnRGbGFzaF90aW1lcigyMCk7IC8vIEJsaW5rcyBmb3IgdmlzdWFsIGluZGljYXRpb24gb2YgZW5jb2RlciBtb3ZlbWVudAovLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdWxkIGJlIGEgYnV6emVyIGluc3RlYWQsIGlmIGRlc2lyZWQuCi8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3IgZGVsZXRlZCBlbnRpcmVseS4KT25EZWxheV90bXIgc29sZW5vaWRPTl90aW1lcigzMDAwKTsgLy8gQWN0dWF0ZSBtZWNoYW5pY2FsIGxvY2sgcmVsZWFzZQpGbGFzaGVyX3RtciBtb2RlRmxhc2hlcl90aW1lcigxMDAwLCAyMDApOyAvLyAxIHNlYy4gcGVyaW9kLCAyMDBtcyBvbiB0aW1lCk9uRGVsYXlfdG1yIE5ld0NvbWJvX3RpbWVyKDEwMDApOyAgIC8vIEVudGVyIHNldCBtb2RlIHdoZW4gdGhpcyB0aW1lcyBvdXQKV2F0Y2hEb2dfdG1yIGFjdGl2aXR5X3RpbWVyKDE1MDAwKTsgLy8gUmVzZXQgdG8gaWRsZSBvciBlbnRlciBzbGVlcCBtb2RlIGlmIG5vdGhpbmcgaGFwcGVuaW5nIG9uIHRoZSBlbmNvZGVyCgoKLy8gPT09IFMgRSBUIFUgUCA9PT0KLy8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCnZvaWQgc2V0dXAoKSB7CiAgU2VyaWFsLmJlZ2luKDExNTIwMCk7CiAgU2VyaWFsLnByaW50bG4oX19GSUxFX18pOwogIHBpbk1vZGUoU0VUX1RPX0RFRkFVTFQsIElOUFVUX1BVTExVUCk7CiAgaWYgKGRpZ2l0YWxSZWFkKFNFVF9UT19ERUZBVUxUKSA9PSAwKSB7IC8vIE9wdGlvbmFsIGxvYWQgb2YgZGVmYXVsdCBjb2RlIGF0IHN0YXJ0dXAuCiAgICBFRVBST00ucHV0KEVFUFJPTV9CQVNFLCBsb2NrQ29kZSk7CiAgICBTZXJpYWwucHJpbnRsbigmcXVvdDtEZWZhdWx0IGNvZGUgc2V0ISZxdW90Oyk7CiAgfQogIEVFUFJPTS5nZXQoRUVQUk9NX0JBU0UsIGxvY2tDb2RlKTsgLy8gcmV0cmlldmUgY3VycmVudCBsb2NrIGNvZGUgdG8gUkFNCgogIHBpbk1vZGUoRU5DT0RFUl9QQiwgSU5QVVRfUFVMTFVQKTsKICBQQ0lDUiB8PSAoMSAmbHQ7Jmx0OyBQQ0lFMik7IC8vIGVuYWJsZSBpbnRlcnJ1cHRzIG9uIHBvcnQgRCAtIGZvciB3YWtldXAKCiAgLy8gYXNzaWduIExFRHMgLSB1c2Ugb25ib2FyZCBwaW4gMTMgZm9yIGRpYWwgc3RhdHVzIGluZGljYXRvcgogIHBpbk1vZGUoZGV0ZW50Rmxhc2hMRUQsIE9VVFBVVCk7CiAgLy8gZXh0ZXJuYWwgTEVEICAtIHVzZSBhcyBsb2NrIHNvbGVub2lkIGluZGljYXRvcgogIHBpbk1vZGUobG9ja1NvbGVub2lkLCBPVVRQVVQpOwogIGRpZ2l0YWxXcml0ZShsb2NrU29sZW5vaWQsIEhJR0gpOwogIC8vIGV4dGVybmFsIExFRCAgLSB1c2UgYXMgbW9kZSBpbmRpY2F0b3IKICBwaW5Nb2RlKG1vZGVMRUQsIE9VVFBVVCk7CiAgZGlnaXRhbFdyaXRlKG1vZGVMRUQsIEhJR0gpOwoKICBsb2NrU3RhdGUgPSBGSVJTVF9TQ0FOOwogIGFjdGl2aXR5X3RpbWVyLnNldEVuYWJsZSh0cnVlKTsKfSAvLyBlbmQgb2Ygc2V0dXAKCi8vCi8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0Kdm9pZCBsb29wKCkgewogIC8vIElmIG5vIGFjdGl2aXR5IGNhbmNlbCBhbnkgY29tYm8gc2V0dGluZyBtb2RlcyBhbmQKICAvLyByZXR1cm4gbG9jayB0byBJTklUX0VOVEVSIHN0YXRlLgogIC8vIElmIHBvd2VyIHNhdmUgb3B0aW9uIGVuYWJsZWQsIGdvIHRvIHNsZWVwLgoKICAvLyBJcyBpdCB0aW1lIHRvIHJlc2V0IG9yIGdvIHRvIHNsZWVwPwogIGlmIChhY3Rpdml0eV90aW1lci5nZXREb25lKCkpIHsKICAgIGlzQ2hhbmdlQ29tYm9GbGFnID0gZmFsc2U7CiAgICBsb2NrU3RhdGUgPSBJTklUX0VOVEVSOyAvLyBjYW5jZWwgYW55IGxlZnRvdmVyIGFjdGl2ZSBtb2RlcwojaWZkZWYgUE9XRVJfU0FWRQogICAgZ29Ub1NsZWVwKCk7CiNlbmRpZgogIH0KICAvLyBSZWZyZXNoIHRoZSB0aW1lcnMKCiAgZGV0ZW50Rmxhc2hfdGltZXIudXBkYXRlKCk7CiAgc29sZW5vaWRPTl90aW1lci51cGRhdGUoKTsgLy8gb25EZWxheV90bXIKICBtb2RlRmxhc2hlcl90aW1lci51cGRhdGUoKTsKICBOZXdDb21ib190aW1lci51cGRhdGUoKTsKICBhY3Rpdml0eV90aW1lci51cGRhdGUoKTsgIC8vIG5vIGFjdGl2aXR5IGZvciBYIHNlY29uZHMgaW5pdGlhdGVzCiAgLy8gICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0ZSBtYWNoaW5lIHJlc2V0IG9yIHNsZWVwIG1vZGUKICAvLwogIGRpYWxNb3ZlZCgpOyAvLyBSZWdpc3RlciBkaWFsIHJvdGF0aW9uIGFuZCBkaXJlY3Rpb24KICBlbmNvZGVyRmxhc2hlcigpOyAvLyBGbGFzaCB0aGUgb25ib2FyZCBMRUQgdG8gdmVyaWZ5IG1vdmVtZW50CgogIC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICBzd2l0Y2ggKGxvY2tTdGF0ZSkgewogICAgLyogVGhpcyBzdGF0ZSBtYWNoaW5lIGd1aWRlcyB1cyB0aHJvdWdoIHRoZSBzZXZlcmFsIHBoYXNlcyBvZgogICAgICBsb2NrIG9wZXJhdGlvbi4KICAgICovCiAgICBjYXNlIEZJUlNUX1NDQU46CgogICAgLyogRmFsbHRocm91Z2ggaXMgZGVsaWJlcmF0ZSAqLwoKICAgIGNhc2UgSU5JVF9FTlRFUjoKICAgICAgY2xlYXJUdW1ibGVycygpOwogICAgICBsb2NrU3RhdGUgPSBFTlRFUl9DT01CTzsKICAgICAgaXNDaGFuZ2VDb21ib0ZsYWcgPSBmYWxzZTsKICAgICAgY29kZUVycm9yID0gZmFsc2U7CgogICAgLyogRmFsbHRocm91Z2ggaXMgZGVsaWJlcmF0ZSAqLwoKICAgIGNhc2UgRU5URVJfQ09NQk86CiAgICAgIGdldEVudHJpZXMoKTsgLy8gUmVjb3JkIGNvZGUgaW5wdXRzCiAgICAgIGlmIChjb2RlRXJyb3IpIHsKICAgICAgICBTZXJpYWwucHJpbnQoJnF1b3Q7Y29kZSBlcnJvclxuJnF1b3Q7KTsKICAgICAgICBsb2NrU3RhdGUgPSBJTklUX0VOVEVSOwogICAgICAgIGJyZWFrOwogICAgICB9CiAgICAgIGlmIChyZWFkRW5jb2RlclBCKFBCX1BVTFNFKSkgeyAvLyBVc2VyIHJlcXVlc3QgdG8gb3BlbiBsb2NrCiAgICAgICAgbG9ja1N0YXRlID0gSU5JVF9PUEVOOwogICAgICB9CiAgICAgIGJyZWFrOwoKICAgIGNhc2UgSU5JVF9PUEVOOgojaWZkZWYgRElTUExBWV9MT0NLX0NPREUKICAgICAgZGlzcGxheVR1bWJsZXJzKCk7IC8vIGRpc3BsYXkgbG9jayBjb2RlICZhbXA7IHN1Ym1pdHRlZCBjb2RlCiNlbmRpZgogICAgICBpZiAobWVtY21wKGxvY2tDb2RlLCB0dW1ibGVyRGF0YSwgTUFYX1RVTUJMRVJTKSA9PSAwKSB7CiAgICAgICAgLy8gQ29ycmVjdCBjb21iaW5hdGlvbiBlbnRlcmVkLCBlbmFibGUgbG9jayBzb2xlbm9pZAogICAgICAgIHNvbGVub2lkT05fdGltZXIuc2V0RW5hYmxlKHRydWUpOwogICAgICAgIGxvY2tTdGF0ZSA9IE9QRU5fTE9DSzsKICAgICAgfQogICAgICBlbHNlIHsKICAgICAgICBsb2NrU3RhdGUgPSBJTklUX0VOVEVSOyAvLyB3cm9uZyBjb2RlLCBzdGFydCBvdmVyCiAgICAgIH0KICAgICAgYnJlYWs7CgogICAgY2FzZSBPUEVOX0xPQ0s6Ly8gQWN0dWF0ZSB0aGUgb3BlbmluZyBtZWNoYW5pc20gYW5kIGJlZ2luCiAgICAgIC8vICAgICAgICAgICAgICB0ZXN0aW5nIGZvciBzZXQgbmV3IGNvbWJvIHJlcXVlc3QKICAgICAgTmV3Q29tYm9fdGltZXIuc2V0RW5hYmxlKCFyZWFkRW5jb2RlclBCKFBCX1NUQVRFKSk7IC8vIFN0YXJ0IHdhaXRpbmcgZm9yIHNldCBtb2RlCgogICAgICAvLyBJZiBlbmNvZGVyIFBCIHByZXNzZWQgZm9yIG9uZSBzZWNvbmQgd2hpbGUgc29sZW5vaWQgaXMgb24sIHNldAogICAgICAvLyBpc0NoYW5nZUNvbWJvRmxhZyB0byBlbmFibGUgcHJvbXB0IGZvciBuZXcgY29kZQogICAgICBpZiAoTmV3Q29tYm9fdGltZXIuZ2V0RG9uZSgpIGFuZCBzb2xlbm9pZE9OX3RpbWVyLmdldFJ1bm5pbmcoKSkgewogICAgICAgIGlzQ2hhbmdlQ29tYm9GbGFnID0gdHJ1ZTsgLy8gV2hlbiBidXR0b24gcHJlc3NlZCBmb3Igb25lIHNlY29uZAogICAgICB9CiAgICAgIGlmIChzb2xlbm9pZE9OX3RpbWVyLmdldERvbmUoKSkgeyAvLyBTb2xlbm9pZCBvbiB0aW1lIGVuZHMKICAgICAgICBzb2xlbm9pZE9OX3RpbWVyLnNldEVuYWJsZShmYWxzZSk7CiAgICAgICAgTmV3Q29tYm9fdGltZXIuc2V0RW5hYmxlKGZhbHNlKTsKICAgICAgICBpZiAoaXNDaGFuZ2VDb21ib0ZsYWcpIHsKICAgICAgICAgIGxvY2tTdGF0ZSA9IElOSVRfTkVXOwogICAgICAgIH0KICAgICAgICBlbHNlIGxvY2tTdGF0ZSA9IElOSVRfRU5URVI7CiAgICAgICAgYnJlYWs7CiAgICAgIH0KICAgICAgZWxzZSBicmVhazsKCiAgICAvLyBVc2VyIHJlcXVlc3QgdG8gY2hhbmdlIGxvY2sgY29kZQogICAgY2FzZSBJTklUX05FVzoKICAgICAgY2xlYXJUdW1ibGVycygpOwogICAgICBtb2RlRmxhc2hlcl90aW1lci5zZXRPblRpbWUoNTAwKTsgIC8vIFNldCBmbGFzaCByYXRpbwogICAgICBsb2NrU3RhdGUgPSBORVdfQ09NQk87CgogICAgLyogRmFsbHRocm91Z2ggaXMgZGVsaWJlcmF0ZSAqLwoKICAgIGNhc2UgTkVXX0NPTUJPOgogICAgICBnZXRFbnRyaWVzKCk7IC8vIFJlY29yZCBuZXcgY29kZSBpbnB1dHMKICAgICAgaWYgKGNvZGVFcnJvcikgeyAvLyBUb28gbWFueSBjb2RlcyBlbnRlcmVkLCBhYm9ydAogICAgICAgIFNlcmlhbC5wcmludCgmcXVvdDtjb2RlIGVycm9yXG4mcXVvdDspOwogICAgICAgIGxvY2tTdGF0ZSA9IElOSVRfRU5URVI7CiAgICAgICAgYnJlYWs7CiAgICAgIH0KICAgICAgaWYgKHJlYWRFbmNvZGVyUEIoUEJfUFVMU0UpKSB7CiNpZmRlZiBWRVJJRllfTkVXX0NPTUJPCiAgICAgICAgbG9ja1N0YXRlID0gSU5JVF9WRVJJRlk7IC8vIElmIHZlcmlmaWNhdGlvbiBvcHRpb24gI2RlZmluZWQKICAgICAgICBicmVhazsKI2VuZGlmCiAgICAgICAgLy8gU2V0IG5ldyBjb21ibywgbm8gdmVyaWZ5CiAgICAgICAgc2V0TmV3Q29tYmluYXRpb24oKTsgLy8gWGZyIG5ldyBjb2RlIHRvIHN0b3JhZ2UKICAgICAgICBsb2NrU3RhdGUgPSBJTklUX0VOVEVSOyAvLyBSZXR1cm4gdG8gaWRsZSBzdGF0ZQogICAgICAgIGJyZWFrOwogICAgICB9CiAgICAgIGJyZWFrOwoKICAgIGNhc2UgSU5JVF9WRVJJRlk6IC8vIFByZXBhcmUgZm9yIG5ldyBjb2RlIHZlcmlmaWNhdGlvbgogICAgICAvLyBDb3B5IGZpcnN0IGNvZGUgdG8gc3RhZ2luZyBhcnJheQogICAgICBtZW1jcHkobmV3Q29kZSwgdHVtYmxlckRhdGEsIE1BWF9UVU1CTEVSUyk7IC8vIE1ha2UgYSBjb3B5IG9mIHRoZSBuZXcgY29kZQogICAgICBjbGVhclR1bWJsZXJzKCk7CiAgICAgIG1vZGVGbGFzaGVyX3RpbWVyLnNldE9uVGltZSg5NTApOyAgLy8gQ2hhbmdlIGZsYXNoIHJhdGlvCiAgICAgIGxvY2tTdGF0ZSA9IFZFUklGWV9DT01CTzsKCiAgICAvKiBGYWxsdGhyb3VnaCBpcyBkZWxpYmVyYXRlICovCgogICAgY2FzZSBWRVJJRllfQ09NQk86CiAgICAgIGdldEVudHJpZXMoKTsgLy8gQ29sbGVjdCB2ZXJpZmljYXRpb24gY29kZQogICAgICBpZiAoY29kZUVycm9yKSB7IC8vCiAgICAgICAgU2VyaWFsLnByaW50KCZxdW90O2NvZGUgZXJyb3JcbiZxdW90Oyk7CiAgICAgICAgbG9ja1N0YXRlID0gSU5JVF9FTlRFUjsKICAgICAgICBicmVhazsKICAgICAgfQogICAgICBpZiAocmVhZEVuY29kZXJQQihQQl9QVUxTRSkpIHsgLy8gVXNlciByZXF1ZXN0cyBuZXcgY29kZSB2ZXJpZmljYXRpb24KICAgICAgICBpZiAobWVtY21wKG5ld0NvZGUsIHR1bWJsZXJEYXRhLCBNQVhfVFVNQkxFUlMpID09IDApIHsgLy8gY29tcGFyZSByZWVudGVyZWQgY29kZSB3aXRoIHByZXZpb3VzCiAgICAgICAgICAvLwogICAgICAgICAgLy8gQ29kZXMgbWF0Y2ggLSBzdG9yZSB0byBlZXByb20gYW5kIGFsc28gdG8gbG9ja0NvZGUuCiAgICAgICAgICBzZXROZXdDb21iaW5hdGlvbigpOwogICAgICAgICAgbG9ja1N0YXRlID0gSU5JVF9FTlRFUjsgLy8gUmV0dXJuIHRvIGlkbGUgc3RhdGUKICAgICAgICAgIGJyZWFrOwogICAgICAgIH0KICAgICAgICAvLyBDb2RlcyBkb24ndCBtYXRjaCwgcmVzdGFydCBuZXcgY29kZSB2ZXJpZmljYXRpb24gcHJvY2VzcwogICAgICAgIGVsc2UgbG9ja1N0YXRlID0gSU5JVF9ORVc7CiAgICAgIH0KICAgICAgYnJlYWs7CiAgICBkZWZhdWx0OgogICAgICBsb2NrU3RhdGUgPSBJTklUX0VOVEVSOwogICAgICBicmVhazsKICB9ICAvLyBFbmQgb2YgbG9ja1N0YXRlIHN3aXRjaAoKICAvLy0tLS0tLSAgTyBVIFQgUCBVIFQgUyAgLS0tLS0tLS0tCgogIG1vZGVGbGFzaGVyX3RpbWVyLnNldEVuYWJsZShpc0NoYW5nZUNvbWJvRmxhZyk7CiAgaWYgKG1vZGVGbGFzaGVyX3RpbWVyLmdldEVuYWJsZSgpKSB7CiAgICBkaWdpdGFsV3JpdGUobW9kZUxFRCwgIW1vZGVGbGFzaGVyX3RpbWVyLmdldEZsYXNoKCkpOwogIH0KICBlbHNlIGRpZ2l0YWxXcml0ZShtb2RlTEVELCBMT1cpOyAvLyBMZWF2ZSBtb2RlIExFRCBvbiB0byBpbmRpY2F0ZSB3YWtlZnVsbmVzcwoKICBkaWdpdGFsV3JpdGUobG9ja1NvbGVub2lkLCAhc29sZW5vaWRPTl90aW1lci5nZXRSdW5uaW5nKCkpOyAvLyBlbmVyZ2l6ZSBsb2NrIHNvbGVub2lkCgogIC8vICBkaWdpdGFsV3JpdGUoZGV0ZW50Rmxhc2hMRUQsIGRldGVudEZsYXNoX3RpbWVyLmdldFJ1bm5pbmcoKSk7IC8vIExFRCBvbgogIGRpZ2l0YWxXcml0ZShkZXRlbnRGbGFzaExFRCwgIWRldGVudEZsYXNoX3RpbWVyLmdldFJ1bm5pbmcoKSk7IC8vIExFRCBvbgp9Ci8vICAtLS0tLS0tLS0tLS0tLSAgRSBOIEQgIE8gRiAgTCBPIE8gUCAgPT09PT09PT09PT09PT0=
/* ENCODER OPERATED COMBINATION LOCK V 3.2
Copyright 2019 by Doug Pirkey
This work is licensed under the Creative Commons Attribution 4.0 International License.
To view a copy of this license, visit http://c...content-available-to-author-only...s.org/licenses/by/4.0/.
A simulation of a mechanical dial combination lock to run on an Arduino UNO
Program Demonstrates:
EEPROM save/restore
Pin change interrupts
Sleep mode
Self-made timer library
memset(), memcmp(), memcpy()
Rotary encoder w external interrupts
#defines for compile time options
Switch/case state machine
Number of possible combinations is given by n^r:
n = number of different numbers (40)
r = number of tumblers used (5)
So the current configuration yields 102,400,000 possible combinations,
correctly called permutations.
Number lock permutations calculator
https://w...content-available-to-author-only...n.com/statistics/number-lock-permutations.php
*/
//-----------------------------------------------
// EEPROM.h is part of the Arduino library.
// https://w...content-available-to-author-only...o.cc/en/Reference/EEPROM/
// https://c...content-available-to-author-only...s.org/licenses/by-sa/3.0/
#include <EEPROM.h> // For storage/retrieval of lock code
//-----------------------------------------------
// Change these two numbers to the pins connected to your encoder.
// Best Performance: both pins have interrupt capability
// Good Performance: only the first pin has interrupt capability
// Low Performance: neither pin has interrupt capability
// Refer to the link for the rotary encoder license
// PaulStoffregen's GitHub page for the encoder library - https://g...content-available-to-author-only...b.com/PaulStoffregen/Encoder
// license description - https://g...content-available-to-author-only...b.com/PaulStoffregen/Encoder/blob/master/Encoder.h
#include <Encoder.h>
Encoder ComboDial(2, 3);
//---------------------------------------------
#include "Multi_Timer.h" // self-made timer library
//----------------------------------------------
/* Sleep library is copyright Microchip.
https://w...content-available-to-author-only...u.org/avr-libc/user-manual/sleep_8h_source.html.
Copyright (c) 2002, 2004 Theodore A. Roth
Copyright (c) 2004, 2007, 2008 Eric B. Weddington
Copyright (c) 2005, 2006, 2007 Joerg Wunsch
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
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.
Neither the name of the copyright holders nor the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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 <avr/sleep.h>
//
// **** Defines to control runtime features ****
//
#define POWER_SAVE // enables processor power down feature
//
#define VERIFY_NEW_COMBO // enables new combo verification code in state machine
//
#define DISPLAY_LOCK_CODE // print stored code and entered code on serial monitor
//
// ================ Constants ==============
const uint8_t INTPIN1 = 2; // Rotary encoder interrupt on this Arduino Uno pin.
const uint8_t INTPIN2 = 3; // Rotary encoder interrupt on this Arduino Uno pin.
const uint8_t ENCODER_PB = 5; // Encoder pushbutton input
const uint8_t lockSolenoid = 7; // +5--/\/\/- 330Ω -->|--DIO7
const uint8_t SET_TO_DEFAULT = 8; // Pin held low at power-up resets to default combo - 221
const uint8_t modeLED = 9; // +5--/\/\/- 330Ω -->|--DIO9
const uint8_t detentFlashLED = 12; // +5--/\/\/- 330Ω -->|--DI12
const uint8_t MAX_TUMBLERS = 5; // number of possible code entries
const uint8_t MAX_TUMBLER_CODE = 40; // max number of dial turns per code entry.
const unsigned int EEPROM_BASE = 20; // starting EEPROM address for code storage
const bool CW = true; // Encoder direction
const bool CCW = !CW; // booleans
const bool PB_PULSE = true; // readEncoderPB argument
const bool PB_STATE = false; // readEncoderPB argument
// ================= Variables ====================
uint8_t tumblerData[MAX_TUMBLERS]; // holds numbers entered for opening or combo setting
uint8_t lockCode[] {2, 2, 1, 0, 0}; // holds working combination to open lock.
// 221 is default for reset/troubleshooting
uint8_t newCode[MAX_TUMBLERS]; // temp storage of changed code
int8_t workingTumbler = -1; // which code number is being entered
bool isEncoderDirectionCW; // clockwise/counterclockwise indicator
bool isEncoderPBPressed;
bool telltale = false; // debugging aid
bool isChangeComboFlag;
bool codeError; // Too many numbers entered
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers
bool encoderTurned; // Signals encoder activity
// ============= Define state machine names ============
enum : byte {
FIRST_SCAN,
INIT_ENTER,
ENTER_COMBO,
INIT_OPEN,
OPEN_LOCK,
INIT_NEW,
NEW_COMBO,
INIT_VERIFY,
VERIFY_COMBO,
} lockState;
// Timers - from Multi_timer.h
OnDelay_tmr detentFlash_timer(20); // Blinks for visual indication of encoder movement
// could be a buzzer instead, if desired.
// or deleted entirely.
OnDelay_tmr solenoidON_timer(3000); // Actuate mechanical lock release
Flasher_tmr modeFlasher_timer(1000, 200); // 1 sec. period, 200ms on time
OnDelay_tmr NewCombo_timer(1000); // Enter set mode when this times out
WatchDog_tmr activity_timer(15000); // Reset to idle or enter sleep mode if nothing happening on the encoder
// === S E T U P ===
//----------------------------------------------------------
void setup() {
Serial.begin(115200);
Serial.println(__FILE__);
pinMode(SET_TO_DEFAULT, INPUT_PULLUP);
if (digitalRead(SET_TO_DEFAULT) == 0) { // Optional load of default code at startup.
EEPROM.put(EEPROM_BASE, lockCode);
Serial.println("Default code set!");
}
EEPROM.get(EEPROM_BASE, lockCode); // retrieve current lock code to RAM
pinMode(ENCODER_PB, INPUT_PULLUP);
PCICR |= (1 << PCIE2); // enable interrupts on port D - for wakeup
// assign LEDs - use onboard pin 13 for dial status indicator
pinMode(detentFlashLED, OUTPUT);
// external LED - use as lock solenoid indicator
pinMode(lockSolenoid, OUTPUT);
digitalWrite(lockSolenoid, HIGH);
// external LED - use as mode indicator
pinMode(modeLED, OUTPUT);
digitalWrite(modeLED, HIGH);
lockState = FIRST_SCAN;
activity_timer.setEnable(true);
} // end of setup
//
//--------------------------------------------------------
void loop() {
// If no activity cancel any combo setting modes and
// return lock to INIT_ENTER state.
// If power save option enabled, go to sleep.
// Is it time to reset or go to sleep?
if (activity_timer.getDone()) {
isChangeComboFlag = false;
lockState = INIT_ENTER; // cancel any leftover active modes
#ifdef POWER_SAVE
goToSleep();
#endif
}
// Refresh the timers
detentFlash_timer.update();
solenoidON_timer.update(); // onDelay_tmr
modeFlasher_timer.update();
NewCombo_timer.update();
activity_timer.update(); // no activity for X seconds initiates
// state machine reset or sleep mode
//
dialMoved(); // Register dial rotation and direction
encoderFlasher(); // Flash the onboard LED to verify movement
//-----------------------------------------------------------
switch (lockState) {
/* This state machine guides us through the several phases of
lock operation.
*/
case FIRST_SCAN:
/* Fallthrough is deliberate */
case INIT_ENTER:
clearTumblers();
lockState = ENTER_COMBO;
isChangeComboFlag = false;
codeError = false;
/* Fallthrough is deliberate */
case ENTER_COMBO:
getEntries(); // Record code inputs
if (codeError) {
Serial.print("code error\n");
lockState = INIT_ENTER;
break;
}
if (readEncoderPB(PB_PULSE)) { // User request to open lock
lockState = INIT_OPEN;
}
break;
case INIT_OPEN:
#ifdef DISPLAY_LOCK_CODE
displayTumblers(); // display lock code & submitted code
#endif
if (memcmp(lockCode, tumblerData, MAX_TUMBLERS) == 0) {
// Correct combination entered, enable lock solenoid
solenoidON_timer.setEnable(true);
lockState = OPEN_LOCK;
}
else {
lockState = INIT_ENTER; // wrong code, start over
}
break;
case OPEN_LOCK:// Actuate the opening mechanism and begin
// testing for set new combo request
NewCombo_timer.setEnable(!readEncoderPB(PB_STATE)); // Start waiting for set mode
// If encoder PB pressed for one second while solenoid is on, set
// isChangeComboFlag to enable prompt for new code
if (NewCombo_timer.getDone() and solenoidON_timer.getRunning()) {
isChangeComboFlag = true; // When button pressed for one second
}
if (solenoidON_timer.getDone()) { // Solenoid on time ends
solenoidON_timer.setEnable(false);
NewCombo_timer.setEnable(false);
if (isChangeComboFlag) {
lockState = INIT_NEW;
}
else lockState = INIT_ENTER;
break;
}
else break;
// User request to change lock code
case INIT_NEW:
clearTumblers();
modeFlasher_timer.setOnTime(500); // Set flash ratio
lockState = NEW_COMBO;
/* Fallthrough is deliberate */
case NEW_COMBO:
getEntries(); // Record new code inputs
if (codeError) { // Too many codes entered, abort
Serial.print("code error\n");
lockState = INIT_ENTER;
break;
}
if (readEncoderPB(PB_PULSE)) {
#ifdef VERIFY_NEW_COMBO
lockState = INIT_VERIFY; // If verification option #defined
break;
#endif
// Set new combo, no verify
setNewCombination(); // Xfr new code to storage
lockState = INIT_ENTER; // Return to idle state
break;
}
break;
case INIT_VERIFY: // Prepare for new code verification
// Copy first code to staging array
memcpy(newCode, tumblerData, MAX_TUMBLERS); // Make a copy of the new code
clearTumblers();
modeFlasher_timer.setOnTime(950); // Change flash ratio
lockState = VERIFY_COMBO;
/* Fallthrough is deliberate */
case VERIFY_COMBO:
getEntries(); // Collect verification code
if (codeError) { //
Serial.print("code error\n");
lockState = INIT_ENTER;
break;
}
if (readEncoderPB(PB_PULSE)) { // User requests new code verification
if (memcmp(newCode, tumblerData, MAX_TUMBLERS) == 0) { // compare reentered code with previous
//
// Codes match - store to eeprom and also to lockCode.
setNewCombination();
lockState = INIT_ENTER; // Return to idle state
break;
}
// Codes don't match, restart new code verification process
else lockState = INIT_NEW;
}
break;
default:
lockState = INIT_ENTER;
break;
} // End of lockState switch
//------ O U T P U T S ---------
modeFlasher_timer.setEnable(isChangeComboFlag);
if (modeFlasher_timer.getEnable()) {
digitalWrite(modeLED, !modeFlasher_timer.getFlash());
}
else digitalWrite(modeLED, LOW); // Leave mode LED on to indicate wakefulness
digitalWrite(lockSolenoid, !solenoidON_timer.getRunning()); // energize lock solenoid
// digitalWrite(detentFlashLED, detentFlash_timer.getRunning()); // LED on
digitalWrite(detentFlashLED, !detentFlash_timer.getRunning()); // LED on
}
// -------------- E N D O F L O O P ==============