├── README.md ├── sc-list.txt ├── mac └── ZAUTHENTICATE.mac ├── Led.ino ├── LICENSE ├── Keypadtest.ino ├── cls └── Arduino │ ├── Habr.cls │ ├── Cube.cls │ ├── Info.cls │ ├── Keypad.cls │ └── Delegated.cls ├── dfi └── Arduino │ ├── Main.dashboard.xml │ ├── NightMeasures.dashboard.xml │ ├── NightMeasures02.dashboard.xml │ ├── Humidity02.pivot.xml │ ├── Brightness02.pivot.xml │ ├── Temperature02.pivot.xml │ ├── Humidity.pivot.xml │ ├── Brightness.pivot.xml │ ├── Temperature.pivot.xml │ └── BrightnessEd.pivot.xml ├── Info_ru.ino ├── Info.ino └── Delegated ├── functions.ino └── Delegated.ino /README.md: -------------------------------------------------------------------------------- 1 | # ArduinoSnippets 2 | Connect your Arduino to InterSystems IRIS or Caché via com porrt (or usb<->com) 3 | 4 | # Installation 5 | Import xml into your Caché instanse, set Arduino.Keypad:SerialPort parameter to your port, compile and you can run availible methods. 6 | 7 | # Arduino 8 | Info.ino or Info_ru.ino contain code for Arduino. 9 | -------------------------------------------------------------------------------- /sc-list.txt: -------------------------------------------------------------------------------- 1 | Arduino-Brightness.pivot.dfi 2 | Arduino-Brightness02.pivot.dfi 3 | Arduino-BrightnessEd.pivot.dfi 4 | Arduino-Humidity.pivot.dfi 5 | Arduino-Humidity02.pivot.dfi 6 | Arduino-Main.dashboard.dfi 7 | Arduino-NightMeasures.dashboard.dfi 8 | Arduino-NightMeasures02.dashboard.dfi 9 | Arduino-Temperature.pivot.dfi 10 | Arduino-Temperature02.pivot.dfi 11 | Arduino.pkg 12 | -------------------------------------------------------------------------------- /mac/ZAUTHENTICATE.mac: -------------------------------------------------------------------------------- 1 | ROUTINE ZAUTHENTICATE 2 | ZAUTHENTICATE(ServiceName,Namespace,Username,Password,Credentials,Properties) PUBLIC { 3 | #Include %occStatus 4 | Write "Logged as " _ $Username 5 | Quit $$$OK 6 | } 7 | 8 | GetCredentials(ServiceName,Namespace,Username,Password,Credentials) Public { 9 | #Include %occErrors 10 | #Include %occStatus 11 | Quit ##class(Arduino.Delegated).GetCredentials(.Username, .Password) 12 | } 13 | 14 | -------------------------------------------------------------------------------- /Led.ino: -------------------------------------------------------------------------------- 1 | /* Led.ino 2 | * 3 | * Пример получения данных по COM порту 4 | * Подключите светодиод к выводу ledPin 5 | * 6 | */ 7 | 8 | // Вывод светодиода (цифровой) 9 | #define ledpin 8 10 | 11 | // "Буфер" поступающих данных 12 | String inString = ""; 13 | 14 | void setup() { 15 | Serial.begin(9600); 16 | pinMode(ledpin, OUTPUT); 17 | digitalWrite(ledpin, LOW); 18 | } 19 | 20 | void loop() { 21 | // Получаем данные из COM порта 22 | while (Serial.available() > 0) { 23 | int inChar = Serial.read(); 24 | if (isDigit(inChar)) { 25 | // Получаем 1 символ, 26 | // Прибавляем его к строке 27 | inString += (char)inChar; 28 | } 29 | 30 | // Доходим до новой строки 31 | if (inChar == '\n') { 32 | // Включаем светодиод 33 | digitalWrite(ledpin, HIGH); 34 | int time = inString.toInt(); 35 | delay(time); 36 | digitalWrite(ledpin, LOW); 37 | // Обнуляем полученную строку 38 | inString = ""; 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 InterSystems Corp. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Keypadtest.ino: -------------------------------------------------------------------------------- 1 | /* Keypadtest.ino 2 | * 3 | * Пример использования библиотеки Keypad 4 | * Подключите Keypad к выводам Arduino указанным в 5 | * rowPins[] and colPins[]. 6 | * 7 | */ 8 | 9 | // Репозиторий библиотеки: 10 | // https://github.com/Chris--A/Keypad 11 | #include 12 | 13 | const byte ROWS = 4; // Четыре строки 14 | const byte COLS = 4; // Три столбцы 15 | // Карта соответствия кнопок и символов 16 | char keys[ROWS][COLS] = { 17 | {'1','2','3','A'}, 18 | {'4','5','6','B'}, 19 | {'7','8','9','C'}, 20 | {'*','0','#','D'} 21 | }; 22 | // Подключите разьёмы keypad 1-8 (сверху-вниз) к Arduino разьёмам 11-4. 1->11, 2->10, ... , 8->4 23 | // Подключите keypad ROW0, ROW1, ROW2 и ROW3 к этим выводам Arduino 24 | byte rowPins[ROWS] = { 7, 6, 5, 4 }; 25 | // Подключите keypad COL0, COL1 and COL2 к этим выводам Arduino 26 | byte colPins[COLS] = { 8, 9, 10, 11 }; 27 | 28 | // Инициализация Keypad 29 | Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); 30 | 31 | #define ledpin 13 32 | 33 | void setup() 34 | { 35 | Serial.begin(9600); 36 | } 37 | 38 | void loop() 39 | { 40 | char key = kpd.getKey(); // Поолучаем нажатую кнопку 41 | if(key) 42 | { 43 | switch (key) 44 | { 45 | case '#': 46 | Serial.println(); 47 | default: 48 | Serial.print(key); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /cls/Arduino/Habr.cls: -------------------------------------------------------------------------------- 1 | Class Arduino.Habr Extends %Persistent 2 | { 3 | 4 | /// Порт, к которому подключается Arduino 5 | Parameter SerialPort As %String = "com5"; 6 | 7 | /// Отправляем на порт строку 1000\n 8 | ClassMethod SendSerial(port = {..#SerialPort}) 9 | { 10 | open port:(:::" 0801n0":/BAUD=9600) // Открываем устройство 11 | set old = $IO // Записываем текущее устройство ввода-вывода 12 | use port // Переключаемся на com порт 13 | write $c(10) // Отправка пробного пакета данных 14 | hang 1 15 | write 1000 _$c(10) // Передаём строку 1000\n 16 | use old // Переключаем вывод на терминал 17 | close port // Закрываем устройство 18 | } 19 | 20 | /// Поручение одной строки данных (до конца строки) 21 | ClassMethod ReceiveOneLine(port = {..#SerialPort}) As %String 22 | { 23 | set str="" 24 | try { 25 | open port:(:::" 0801n0":/BAUD=9600) 26 | set old = $io //Keep track of the original device 27 | use port 28 | read str //Read until a termination character is reached 29 | use old 30 | close port 31 | } catch ex { 32 | close port 33 | } 34 | return str 35 | } 36 | 37 | Storage Default 38 | { 39 | 40 | 41 | %%CLASSNAME 42 | 43 | 44 | ^Arduino.HabrD 45 | HabrDefaultData 46 | ^Arduino.HabrD 47 | ^Arduino.HabrI 48 | ^Arduino.HabrS 49 | %Storage.Persistent 50 | } 51 | 52 | } 53 | 54 | -------------------------------------------------------------------------------- /dfi/Arduino/Main.dashboard.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /cls/Arduino/Cube.cls: -------------------------------------------------------------------------------- 1 | /// Класс с данными с платы 2 | Class Arduino.Cube Extends %DeepSee.CubeDefinition [ DependsOn = Arduino.Info, ProcedureBlock ] 3 | { 4 | 5 | Parameter DOMAIN; 6 | 7 | /// Cube definition from Architect. 8 | XData Cube [ XMLNamespace = "http://www.intersystems.com/deepsee" ] 9 | { 10 | 11 | 21 | 22 | 23 | 24 | 25 | } 26 | 27 | } 28 | 29 | -------------------------------------------------------------------------------- /Info_ru.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Программа, регистрирующая влажность, температуру и яркость 3 | * Отправляет результаты на COM port 4 | * Формат вывода: H=1.0;T=1.0;LL=1; 5 | */ 6 | 7 | //Пин фоторезистора (аналоговый) 8 | int lightPin = 0; 9 | 10 | // Пин DHT-11 (цифровой) 11 | int DHpin = 8; 12 | 13 | // Массив, хранящий данные DHT-11 14 | byte dat[5]; 15 | 16 | // Первоначальная настройка 17 | void setup() 18 | { 19 | Serial.begin(9600); 20 | pinMode(DHpin,OUTPUT); 21 | } 22 | 23 | /* 24 | * Выполняется после setup() 25 | * Основной бесконечный цикл 26 | */ 27 | void loop() 28 | { 29 | delay(1000); // Замер примерно 1 раз в секунду 30 | int lightLevel = analogRead(lightPin); //Получаем уровень освещённости 31 | 32 | temp_hum(); // Получаем температуру и влажность в переменную dat 33 | // И выводим результат 34 | Serial.print("H="); 35 | Serial.print(dat[0], DEC); 36 | Serial.print('.'); 37 | Serial.print(dat[1],DEC); 38 | Serial.print(";T="); 39 | Serial.print(dat[2], DEC); 40 | Serial.print('.'); 41 | Serial.print(dat[3],DEC); 42 | Serial.print(";LL="); 43 | Serial.print(lightLevel); 44 | Serial.println(";"); 45 | } 46 | 47 | // Получить данные от DHT-11 в dat 48 | void temp_hum() 49 | { 50 | digitalWrite(DHpin,LOW); 51 | delay(30); 52 | digitalWrite(DHpin,HIGH); 53 | delayMicroseconds(40); 54 | pinMode(DHpin,INPUT); 55 | while(digitalRead(DHpin) == HIGH); 56 | delayMicroseconds(80); 57 | if(digitalRead(DHpin) == LOW); 58 | delayMicroseconds(80); 59 | for(int i=0;i<4;i++) 60 | { 61 | dat[i] = read_data(); 62 | } 63 | pinMode(DHpin,OUTPUT); 64 | digitalWrite(DHpin,HIGH); 65 | } 66 | 67 | // Получить часть данных от DHT-11 68 | byte read_data() 69 | { 70 | byte data; 71 | for(int i=0; i<8; i++) 72 | { 73 | if(digitalRead(DHpin) == LOW) 74 | { 75 | while(digitalRead(DHpin) == LOW); 76 | delayMicroseconds(30); 77 | if(digitalRead(DHpin) == HIGH) 78 | { 79 | data |= (1<<(7-i)); 80 | } 81 | while(digitalRead(DHpin) == HIGH); 82 | } 83 | } 84 | return data; 85 | } -------------------------------------------------------------------------------- /Info.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * A simple programme that will record humidity, temperature and brightness 3 | * temperature and brightness and send them to COM port 4 | * Output format: H=1.0;T=1.0;LL=1; 5 | * 6 | */ 7 | 8 | //PhotoResistor Pin 9 | int lightPin = 0; //the analog pin the photoresistor is 10 | //connected to 11 | //the photoresistor is not calibrated to any units so 12 | //this is simply a raw sensor value (relative light) 13 | 14 | 15 | // DHT-11 Brick pin 16 | int DHpin = 8; 17 | 18 | byte dat[5]; 19 | 20 | //LED Pin 21 | int ledPin = 13; //the pin the LED is connected to 22 | //we are controlling brightness so 23 | //we use one of the PWM (pulse width 24 | // modulation pins) 25 | 26 | byte read_data() 27 | { 28 | byte data; 29 | for(int i=0; i<8; i++) 30 | { 31 | if(digitalRead(DHpin) == LOW) 32 | { 33 | while(digitalRead(DHpin) == LOW); 34 | delayMicroseconds(30); 35 | if(digitalRead(DHpin) == HIGH) 36 | data |= (1<<(7-i)); 37 | 38 | while(digitalRead(DHpin) == HIGH); 39 | } 40 | } 41 | return data; 42 | } 43 | 44 | // Get data from DHT-11 Brick sensor 45 | void start_test() 46 | { 47 | digitalWrite(DHpin,LOW); 48 | delay(30); 49 | digitalWrite(DHpin,HIGH); 50 | delayMicroseconds(40); 51 | pinMode(DHpin,INPUT); 52 | while(digitalRead(DHpin) == HIGH); 53 | delayMicroseconds(80); 54 | if(digitalRead(DHpin) == LOW); 55 | delayMicroseconds(80); 56 | for(int i=0;i<4;i++) 57 | dat[i] = read_data(); 58 | pinMode(DHpin,OUTPUT); 59 | digitalWrite(DHpin,HIGH); 60 | } 61 | 62 | 63 | // Initial setup 64 | void setup() 65 | { 66 | Serial.begin(9600); 67 | pinMode(DHpin,OUTPUT); 68 | } 69 | /* 70 | * loop() - this function will start after setup 71 | * finishes and then repeat 72 | */ 73 | void loop() 74 | { 75 | delay(1000); 76 | int lightLevel = analogRead(lightPin); //Read the lightlevel 77 | 78 | start_test(); 79 | Serial.print("H="); 80 | Serial.print(dat[0], DEC); 81 | Serial.print('.'); 82 | Serial.print(dat[1],DEC); 83 | Serial.print(";T="); 84 | Serial.print(dat[2], DEC); 85 | Serial.print('.'); 86 | Serial.print(dat[3],DEC); 87 | Serial.print(";LL="); 88 | Serial.print(lightLevel); 89 | Serial.println(";"); 90 | } 91 | -------------------------------------------------------------------------------- /cls/Arduino/Info.cls: -------------------------------------------------------------------------------- 1 | Class Arduino.Info Extends %Persistent 2 | { 3 | 4 | Parameter SerialPort As %String = "com3"; 5 | 6 | Property DateTime As %DateTime; 7 | 8 | Property Temperature As %Double; 9 | 10 | Property Humidity As %Double(MAXVAL = 100, MINVAL = 0); 11 | 12 | Property Brightness As %Double(MAXVAL = 100, MINVAL = 0); 13 | 14 | Property Volume As %Double(MAXVAL = 100, MINVAL = 0); 15 | 16 | ClassMethod AddNew(Temperature = 0, Humidity = 0, Brightness = 0, Volume = 0) 17 | { 18 | set obj = ..%New() 19 | set obj.DateTime=$ZDT($H,3,1) 20 | set obj.Temperature=Temperature 21 | set obj.Humidity=Humidity 22 | set obj.Brightness=Brightness/1023*100 23 | set obj.Volume=Volume 24 | w $SYSTEM.Status.DisplayError(obj.%Save()) 25 | } 26 | 27 | /// Receive one line at a time, using common terminating characters (i.e., CR/LF) 28 | /// Infinite loop, terminated by / etc. 29 | /// do ##class(Arduino.Info).ReceiveSerial() 30 | ClassMethod ReceiveSerial(pSerialPort = {..#SerialPort}) 31 | { 32 | try { 33 | //Parameters used to open the serial device: 34 | // portstate = " 0801n0" - by byte position: 35 | // 1: space indicates "don't disconnect the port" 36 | // 2: 0 indicates "don't use modem control" 37 | // 3: 8 indicates 8 data bits 38 | // 4: 0 indicates no parity 39 | // 5: 1 indicates one stop bit 40 | // 6: n indicates that flow control is disabled 41 | // 7: 0 indicates disable DTR 42 | // /BAUD=9600 determines the baud rate, of course. 43 | open pSerialPort:(:::" 0801n0":/BAUD=9600) 44 | set old = $io //Keep track of the original device 45 | for { 46 | use pSerialPort 47 | read x //Read until a termination character is reached 48 | if (x '= "") { 49 | use old 50 | set Humidity = $p($p(x,";",1),"=",2) 51 | set Temperature = $p($p(x,";",2),"=",2) 52 | set Brightness = $p($p(x,";",3),"=",2) 53 | do ..AddNew(Temperature,Humidity,Brightness) 54 | } 55 | } 56 | } catch anyError { 57 | close pSerialPort 58 | } 59 | } 60 | 61 | Storage Default 62 | { 63 | 64 | 65 | %%CLASSNAME 66 | 67 | 68 | DateTime 69 | 70 | 71 | Temperature 72 | 73 | 74 | Humidity 75 | 76 | 77 | Brightness 78 | 79 | 80 | Volume 81 | 82 | 83 | ^Arduino.InfoD 84 | InfoDefaultData 85 | ^Arduino.InfoD 86 | ^Arduino.InfoI 87 | ^Arduino.InfoS 88 | %Storage.Persistent 89 | } 90 | 91 | } 92 | 93 | -------------------------------------------------------------------------------- /dfi/Arduino/NightMeasures.dashboard.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /dfi/Arduino/NightMeasures02.dashboard.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /dfi/Arduino/Humidity02.pivot.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /dfi/Arduino/Brightness02.pivot.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /dfi/Arduino/Temperature02.pivot.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /dfi/Arduino/Humidity.pivot.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /dfi/Arduino/Brightness.pivot.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /dfi/Arduino/Temperature.pivot.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /dfi/Arduino/BrightnessEd.pivot.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Delegated/functions.ino: -------------------------------------------------------------------------------- 1 | 2 | 3 | int writeBlock(int blockNumber, byte arrayAddress[]) 4 | { 5 | //this makes sure that we only write into data blocks. Every 4th block is a trailer block for the access/security info. 6 | int largestModulo4Number = blockNumber / 4 * 4; 7 | int trailerBlock = largestModulo4Number + 3; //determine trailer block for the sector 8 | if (blockNumber > 2 && (blockNumber + 1) % 4 == 0) { 9 | Serial.print(blockNumber); //block number is a trailer block (modulo 4); quit and send error code 2 10 | Serial.println(" is a trailer block:"); 11 | return 2; 12 | } 13 | //Serial.print(blockNumber); 14 | //Serial.println(" is a data block:"); 15 | 16 | /*****************************************authentication of the desired block for access***********************************************************/ 17 | byte status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid)); 18 | //byte PCD_Authenticate(byte command, byte blockAddr, MIFARE_Key *key, Uid *uid); 19 | //this method is used to authenticate a certain block for writing or reading 20 | //command: See enumerations above -> PICC_CMD_MF_AUTH_KEY_A = 0x60 (=1100000), // this command performs authentication with Key A 21 | //blockAddr is the number of the block from 0 to 15. 22 | //MIFARE_Key *key is a pointer to the MIFARE_Key struct defined above, this struct needs to be defined for each block. New cards have all A/B= FF FF FF FF FF FF 23 | //Uid *uid is a pointer to the UID struct that contains the user ID of the card. 24 | if (status != MFRC522::STATUS_OK) { 25 | Serial.print("PCD_Authenticate() failed: "); 26 | Serial.println(mfrc522.GetStatusCodeName(status)); 27 | return 3;//return "3" as error message 28 | } 29 | //it appears the authentication needs to be made before every block read/write within a specific sector. 30 | //If a different sector is being authenticated access to the previous one is lost. 31 | 32 | 33 | /*****************************************writing the block***********************************************************/ 34 | 35 | status = mfrc522.MIFARE_Write(blockNumber, arrayAddress, 16);//valueBlockA is the block number, MIFARE_Write(block number (0-15), byte array containing 16 values, number of bytes in block (=16)) 36 | //status = mfrc522.MIFARE_Write(9, value1Block, 16); 37 | if (status != MFRC522::STATUS_OK) { 38 | Serial.print("MIFARE_Write() failed: "); 39 | Serial.println(mfrc522.GetStatusCodeName(status)); 40 | return 4;//return "4" as error message 41 | } 42 | //Serial.println("block was written"); 43 | } 44 | 45 | 46 | int readBlock(int blockNumber, byte arrayAddress[]) 47 | { 48 | int largestModulo4Number = blockNumber / 4 * 4; 49 | int trailerBlock = largestModulo4Number + 3; //determine trailer block for the sector 50 | 51 | /*****************************************authentication of the desired block for access***********************************************************/ 52 | byte status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid)); 53 | //byte PCD_Authenticate(byte command, byte blockAddr, MIFARE_Key *key, Uid *uid); 54 | //this method is used to authenticate a certain block for writing or reading 55 | //command: See enumerations above -> PICC_CMD_MF_AUTH_KEY_A = 0x60 (=1100000), // this command performs authentication with Key A 56 | //blockAddr is the number of the block from 0 to 15. 57 | //MIFARE_Key *key is a pointer to the MIFARE_Key struct defined above, this struct needs to be defined for each block. New cards have all A/B= FF FF FF FF FF FF 58 | //Uid *uid is a pointer to the UID struct that contains the user ID of the card. 59 | if (status != MFRC522::STATUS_OK) { 60 | Serial.print("PCD_Authenticate() failed (read): "); 61 | Serial.println(mfrc522.GetStatusCodeName(status)); 62 | return 3;//return "3" as error message 63 | } 64 | //it appears the authentication needs to be made before every block read/write within a specific sector. 65 | //If a different sector is being authenticated access to the previous one is lost. 66 | 67 | 68 | /*****************************************reading a block***********************************************************/ 69 | 70 | byte buffersize = 18;//we need to define a variable with the read buffer size, since the MIFARE_Read method below needs a pointer to the variable that contains the size... 71 | status = mfrc522.MIFARE_Read(blockNumber, arrayAddress, &buffersize);//&buffersize is a pointer to the buffersize variable; MIFARE_Read requires a pointer instead of just a number 72 | if (status != MFRC522::STATUS_OK) { 73 | Serial.print("MIFARE_read() failed: "); 74 | Serial.println(mfrc522.GetStatusCodeName(status)); 75 | return 4;//return "4" as error message 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /cls/Arduino/Keypad.cls: -------------------------------------------------------------------------------- 1 | /// See for general reference on the I/O commands used here: 2 | /// http://docs.intersystems.com/cache_latest/csp/docbook/DocBook.UI.Page.cls?KEY=GIOD_termio#GIOD_tio_openuse 3 | /// based on https://code.intersystems.com/code/Code.View.Code.cls?ID=856&title=read-serial-input-from-arduino 4 | Class Arduino.Keypad Extends %RegisteredObject 5 | { 6 | 7 | Parameter SerialPort As %String = "com5"; 8 | 9 | /// Receive one line at a time, using common terminating characters (i.e., CR/LF) 10 | /// Infinite loop, terminated by / etc. 11 | /// do ##class(Arduino.Keypad).ReceiveSerial() 12 | ClassMethod ReceiveSerial(pSerialPort = {..#SerialPort}) 13 | { 14 | try { 15 | //Parameters used to open the serial device: 16 | // portstate = " 0801n0" - by byte position: 17 | // 1: space indicates "don't disconnect the port" 18 | // 2: 0 indicates "don't use modem control" 19 | // 3: 8 indicates 8 data bits 20 | // 4: 0 indicates no parity 21 | // 5: 1 indicates one stop bit 22 | // 6: n indicates that flow control is disabled 23 | // 7: 0 indicates disable DTR 24 | // /BAUD=9600 determines the baud rate, of course. 25 | open pSerialPort:(:::" 0801n0":/BAUD=9600) 26 | set old = $io //Keep track of the original device 27 | for { 28 | use pSerialPort 29 | read x //Read until a termination character is reached 30 | if (x '= "") { 31 | use old 32 | write x,! 33 | } 34 | } 35 | } catch anyError { 36 | close pSerialPort 37 | } 38 | } 39 | 40 | /// Receive one line at a time, using common terminating characters (i.e., CR/LF) 41 | /// w ##class(Arduino.Keypad).ReceiveOneLine() 42 | ClassMethod ReceiveOneLine(pSerialPort = {..#SerialPort}) As %String 43 | { 44 | set x="" 45 | try { 46 | //Parameters used to open the serial device: 47 | // portstate = " 0801n0" - by byte position: 48 | // 1: space indicates "don't disconnect the port" 49 | // 2: 0 indicates "don't use modem control" 50 | // 3: 8 indicates 8 data bits 51 | // 4: 0 indicates no parity 52 | // 5: 1 indicates one stop bit 53 | // 6: n indicates that flow control is disabled 54 | // 7: 0 indicates disable DTR 55 | // /BAUD=9600 determines the baud rate, of course. 56 | open pSerialPort:(:::" 0801n0":/BAUD=9600) 57 | set old = $io //Keep track of the original device 58 | use pSerialPort 59 | read x //Read until a termination character is reached 60 | use old 61 | close pSerialPort 62 | } catch ex { 63 | close pSerialPort 64 | } 65 | return x 66 | } 67 | 68 | /// Receive one character at a time, without any consideration for terminating characters 69 | /// Infinite loop, terminated by / etc. 70 | ClassMethod ReceiveSerial1Char(pSerialPort = {..#SerialPort}) 71 | { 72 | try { 73 | //Parameters same as above, except operating in "image mode" 74 | //This treats all characters as data 75 | open pSerialPort:(:"I"::" 0801n0":/BAUD=9600) 76 | set old = $io //Keep track of the original device 77 | for { 78 | use pSerialPort 79 | read *x //Read one character at a time 80 | if (x '= "") { 81 | use old 82 | write $c(x) //Convert from decimal to ASCII 83 | } 84 | } 85 | } catch anyError { 86 | close pSerialPort 87 | } 88 | } 89 | 90 | /// Receive one line at a time, using common terminating characters (i.e., CR/LF) 91 | /// Infinite loop, terminated by / etc. 92 | /// do ##class(Arduino.Keypad).SendSerial() 93 | ClassMethod SendSerial1(pSerialPort = {..#SerialPort}) 94 | { 95 | try { 96 | //Parameters used to open the serial device: 97 | // portstate = " 0801n0" - by byte position: 98 | // 1: space indicates "don't disconnect the port" 99 | // 2: 0 indicates "don't use modem control" 100 | // 3: 8 indicates 8 data bits 101 | // 4: 0 indicates no parity 102 | // 5: 1 indicates one stop bit 103 | // 6: n indicates that flow control is disabled 104 | // 7: 0 indicates disable DTR 105 | // /BAUD=9600 determines the baud rate, of course. 106 | open pSerialPort:(:::" 0801n0":/BAUD=9600) 107 | set old = $io //Keep track of the original device 108 | //for { 109 | use pSerialPort 110 | w $c(10) 111 | h 1 112 | w 1000 _$c(10) 113 | use old 114 | close pSerialPort 115 | /*read x //Read until a termination character is reached 116 | if (x '= "") { 117 | use old 118 | write x,! 119 | }*/ 120 | //} 121 | } catch anyError { 122 | close pSerialPort 123 | } 124 | } 125 | 126 | /// Receive one line at a time, using common terminating characters (i.e., CR/LF) 127 | /// Infinite loop, terminated by / etc. 128 | /// do ##class(Arduino.Keypad).SendSerial() 129 | ClassMethod SendSerial() 130 | { 131 | set port = "COM1" // Имя порта 132 | open port:(:::" 0801n0":/BAUD=9600) // Открываем устройство 133 | set old = $io // Записываем текущее устройство ввода-вывода 134 | use port // Переключаемся на com порт 135 | write $c(10) // первоначальное установление соединения 136 | hang 1 137 | write 1000 _$c(10) // Передаём строку 1000\n 138 | use old // Переключаем вывод на терминал 139 | close port // Закрываем устройство 140 | } 141 | 142 | } 143 | 144 | -------------------------------------------------------------------------------- /Delegated/Delegated.ino: -------------------------------------------------------------------------------- 1 | 2 | /****************************************** 3 | Purpose: Learn to use the MF522-AN RFID card reader with InterSystems Caché 4 | Created by: Eduard Lebedyuk 5 | Date: 3/2016 6 | *******************************************/ 7 | 8 | /* 9 | * This sketch uses the MFRC522 Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT. 10 | * The library file MFRC522.h has a wealth of useful info. Please read it. 11 | * The functions are documented in MFRC522.cpp. 12 | * 13 | * Based on code Dr.Leong ( WWW.B2CQSHOP.COM ) 14 | * Created by Miguel Balboa (circuitito.com), Jan, 2012. 15 | * Rewritten by Søren Thing Andersen (access.thing.dk), fall of 2013 (Translation to English, refactored, comments, anti collision, cascade levels.) 16 | * Updated by Rudy Schlaf for www.makecourse.com 17 | * 18 | * This library has been released into the public domain. 19 | */ 20 | 21 | 22 | #include //include the SPI bus library 23 | #include //include the RFID reader library 24 | 25 | #define SS_PIN 10 //slave select pin 26 | #define RST_PIN 9 //reset pin 27 | 28 | #define u1b 2 //Block on a card for user1 byte array 29 | #define u2b 4 //Block on a card for user2 byte array 30 | #define p1b 5 //Block on a card for pass1 byte array 31 | #define p2b 6 //Block on a card for pass2 byte array 32 | 33 | MFRC522 mfrc522(SS_PIN, RST_PIN); // instatiate a MFRC522 reader object. 34 | MFRC522::MIFARE_Key key;//create a MIFARE_Key struct named 'key', which will hold the card information 35 | 36 | byte readbackblock[18];//This array is used for reading out a block. The MIFARE_Read method requires a buffer that is at least 18 bytes to hold the 16 bytes of a block. 37 | 38 | String inString = ""; // COM port incoming data buffer 39 | 40 | void setup() { 41 | Serial.begin(9600); // Initialize serial communications with the PC 42 | SPI.begin(); // Init SPI bus 43 | mfrc522.PCD_Init(); // Init MFRC522 card (in case you wonder what PCD means: proximity coupling device) 44 | //Serial.println("Scan a MIFARE Classic card"); 45 | 46 | // Prepare the security key for the read and write functions - all six key bytes are set to 0xFF at chip delivery from the factory. 47 | // Since the cards in the kit are new and the keys were never defined, they are 0xFF 48 | // if we had a card that was programmed by someone else, we would need to know the key to be able to access it. This key would then need to be stored in 'key' instead. 49 | 50 | for (byte i = 0; i < 6; i++) { 51 | key.keyByte[i] = 0xFF;//keyByte is defined in the "MIFARE_Key" 'struct' definition in the .h file of the library 52 | } 53 | 54 | } 55 | 56 | void loop() { 57 | // put your main code here, to run repeatedly: 58 | // Receive data from com port 59 | while (Serial.available() > 0) { 60 | int inChar = Serial.read(); 61 | 62 | if (inChar != '\n') { 63 | inString += (char)inChar; 64 | } else { 65 | // New line 66 | while (!initCard()); // connect to an RFID card 67 | String Action = inString.substring(0, 3); 68 | if (Action == "Set") { 69 | // Write login and pass into the card 70 | setUserAndPassToCard(inString); 71 | } else if (Action == "Get") { 72 | // Read login and pass from the card 73 | readUserAndPassToCom(); 74 | } else { 75 | Serial.println(Action); 76 | } 77 | 78 | disconnectCard(); // disconnect RFID card 79 | inString = ""; 80 | } 81 | } 82 | } 83 | 84 | /// Read blocks with user/pass info and output the to COM port: 85 | /// user1user2@pass1pass2 86 | void readUserAndPassToCom() 87 | { 88 | readBlockToCom(u1b); 89 | readBlockToCom(u2b); 90 | Serial.write("@"); 91 | readBlockToCom(p1b); 92 | readBlockToCom(p2b); 93 | Serial.println(""); 94 | } 95 | 96 | /// Set user/pass info into a card 97 | /// Data: Set@user1@user2@pass1@pass2 98 | /// Data sample: Set@1234567890123456@1234567890123456@1234567890123456@1234567890123456 99 | void setUserAndPassToCard(String Data) { 100 | // Serial.println(Data); 101 | byte user1[16], user2[16], pass1[16], pass2[16]; 102 | 103 | String user1str = inString.substring(4, 20); 104 | String user2str = inString.substring(21, 37); 105 | String pass1str = inString.substring(38, 54); 106 | String pass2str = inString.substring(55, 71); 107 | 108 | stringToArray(user1str, user1, sizeof(user1)); 109 | stringToArray(user2str, user2, sizeof(user2)); 110 | stringToArray(pass1str, pass1, sizeof(pass1)); 111 | stringToArray(pass2str, pass2, sizeof(pass2)); 112 | 113 | writeBlock(u1b, user1); // u1b is the block number, user1 is the block content 114 | writeBlock(u2b, user2); 115 | writeBlock(p1b, pass1); 116 | writeBlock(p2b, pass2); 117 | 118 | Serial.println("Done"); 119 | } 120 | 121 | void stringToArray(String str, byte array[], int arrlength) 122 | { 123 | for (int j = 0 ; j < arrlength ; j++) 124 | { 125 | array[j] = str.charAt(j); 126 | } 127 | } 128 | 129 | bool initCard() 130 | { 131 | // Look for new cards (in case you wonder what PICC means: proximity integrated circuit card) 132 | if ( ! mfrc522.PICC_IsNewCardPresent()) {//if PICC_IsNewCardPresent returns 1, a new card has been found and we continue 133 | return false; //if it did not find a new card is returns a '0' and we return to the start of the loop 134 | } 135 | 136 | // Select one of the cards 137 | if ( ! mfrc522.PICC_ReadCardSerial()) {//if PICC_ReadCardSerial returns 1, the "uid" struct (see MFRC522.h lines 238-45)) contains the ID of the read card. 138 | return false; //if it returns a '0' something went wrong and we return to the start of the loop 139 | } 140 | return true; 141 | } 142 | 143 | void disconnectCard() 144 | { 145 | // Halt PICC 146 | mfrc522.PICC_HaltA(); 147 | // Stop encryption on PCD 148 | mfrc522.PCD_StopCrypto1(); 149 | } 150 | 151 | void readBlockToCom(int number) 152 | { 153 | readBlock(number, readbackblock);//read the block back 154 | for (int j = 0 ; j < 16 ; j++) //print the block contents 155 | { 156 | Serial.write (readbackblock[j]);//Serial.write() transmits the ASCII numbers as human readable characters to serial monitor 157 | } 158 | } 159 | 160 | 161 | 162 | -------------------------------------------------------------------------------- /cls/Arduino/Delegated.cls: -------------------------------------------------------------------------------- 1 | /// Delegated Authentication with Arduino. 2 | /// Installation steps:
3 | /// 1. Connect arduino (and upload C code from Delegated.ino there)
4 | /// 2. Make this class visible in %SYS namespace (import there or map pckage)
5 | /// 3. Set SerialPort parameter to a correct value and recompile the class
6 | /// 4. Run Do ##class(Arduino.Delegated).InitEncryption(Key, IV) 7 | /// 5. Write encrypted user credentials to RFID card with SetCredentials
8 | /// 6. Import ZAUTHENTICATE into %SYS
9 | /// 7. Enable Delegated and password auth for relevant services and/or apps 10 | Class Arduino.Delegated [ Abstract ] 11 | { 12 | 13 | /// Name of a serial port to which Arduino is connected 14 | Parameter SerialPort As %String = "com3"; 15 | 16 | /// Creates managed encryption key.
17 | /// key - Input key material. 18 | /// Key material 16, 24, or 32 characters long (on Unicode systems, with all character values < 256) is used directly. 19 | /// Otherwise, Password-Based Key Derivation Function #2 (PBKDF2) 20 | /// is used with HMAC-SHA-1, 21 | /// no salt, and one iteration 22 | /// to generate an AES key of the next larger valid size (up to 32 bytes). 23 | /// (See RSA Laboratories Public-Key Cryptography Standards #5 for more information.) 24 | ///

25 | /// IV - Initialization vector (optional). 26 | /// If this argument is present it must be 16 characters long (on Unicode systems, with all character values < 256). 27 | /// If this argument is omitted (or is an empty string), a null initialization vector is used. 28 | ///
29 | /// Do ##class(Arduino.Delegated).Init("", "") 30 | ClassMethod Init(Key As %String, IV As %String) 31 | { 32 | New $Namespace 33 | Set $Namespace = "%SYS" 34 | Set ^Arduino("Key")= Key 35 | Set ^Arduino("IV")= IV 36 | } 37 | 38 | /// Send Arduino the command to set credentials on a card to Username/Password (encrypted) 39 | /// Do ##class(Arduino.Delegated).SetCredentials("_SYSTEM", "SYS") 40 | ClassMethod SetCredentials(Username As %String(MAXLEN=15), Password As %String(MAXLEN=15)) As %Status 41 | { 42 | 43 | Set Status = $$$OK 44 | 45 | Set CipherUsername = ..EncryptText(Username) 46 | Set CipherPassword = ..EncryptText(Password) 47 | 48 | Set User1 = $Extract(CipherUsername, 1, 16) 49 | 50 | Set User2 = $Extract(CipherUsername, 17, 32) 51 | Set User2 = ..AppendToString(User2, , 16) 52 | 53 | Set Pass1 = $Extract(CipherPassword, 1, 16) 54 | 55 | Set Pass2 = $Extract(CipherPassword, 17, 32) 56 | Set Pass2 = ..AppendToString(Pass2, , 16) 57 | 58 | Set CommandList = $ListBuild("Set", User1, User2, Pass1, Pass2) 59 | Set Command = $ListToString(CommandList, "@") 60 | 61 | Set Status = ..ExecuteCommand(.Command) 62 | If (Status = "Done") { 63 | Set Status = $$$OK 64 | } Else { 65 | Set Status = $$$ERROR($$$GeneralError, "SetCredentials failure, received: " _ Status) 66 | } 67 | 68 | Return Status 69 | } 70 | 71 | /// Connect to an Arduino device, receive credentials, decode them and set to Username/Password variables. 72 | /// do ##class(Arduino.Delegated).GetCredentials(.Username, .Password) 73 | ClassMethod GetCredentials(Output Username As %String, Output Password As %String) As %Status 74 | { 75 | Kill Username, Password 76 | Set Username = "" 77 | Set Password = "" 78 | Set Status = $$$OK 79 | 80 | Set Credentials = ..ExecuteCommand("Get") 81 | If (($L(Credentials) =65) && ($L(Credentials,"@") = 2)) { 82 | Set CipherUsername = $Piece(Credentials, "@", 1) 83 | Set CipherPassword = $Piece(Credentials, "@", 2) 84 | Set CipherUsername = $Extract(CipherUsername, 1, 24) // we need only first 24 characters 85 | Set CipherPassword = $Extract(CipherPassword, 1, 24) 86 | Set Username = ..DecryptText(CipherUsername) 87 | Set Password = ..DecryptText(CipherPassword) 88 | } Else { 89 | Set Status = $$$ERROR($$$GeneralError, "GetCredentials failure, received: " _ Credentials) 90 | } 91 | 92 | Return Status 93 | } 94 | 95 | /// Send one line at a time, using common terminating characters (i.e., CR) and receive output 96 | /// Possible comands:
97 | /// Get - reads an RFID card and returns information in a format: user@pass
98 | /// Set@user1@user2@pass1@pass2 - sets information on a RFID card 99 | /// in a format: user@pass (where user = user1@user2)
100 | /// Returns output, produced by Arduino 101 | /// w ##class(Arduino.Delegated).ExecuteCommand("Get") 102 | ClassMethod ExecuteCommand(ByRef Command As %String, SerialPort = {..#SerialPort}) As %String 103 | { 104 | set x="" 105 | try { 106 | //Parameters used to open the serial device: 107 | // portstate = " 0801n0" - by byte position: 108 | // 1: space indicates "don't disconnect the port" 109 | // 2: 0 indicates "don't use modem control" 110 | // 3: 8 indicates 8 data bits 111 | // 4: 0 indicates no parity 112 | // 5: 1 indicates one stop bit 113 | // 6: n indicates that flow control is disabled 114 | // 7: 0 indicates disable DTR 115 | // /BAUD=9600 determines the baud rate, of course. 116 | open SerialPort:(:::" 0801n0":/BAUD=9600) 117 | set old = $io //Keep track of the original device 118 | use SerialPort 119 | 120 | write $char(10) 121 | 122 | hang 1 123 | 124 | write Command _ $Char(10) 125 | 126 | read x //Read until a termination character is reached 127 | use old 128 | close SerialPort 129 | } catch ex { 130 | close SerialPort 131 | w $System.Status.GetErrorText(ex.AsStatus()) 132 | } 133 | 134 | return x 135 | } 136 | 137 | /// Get key to encode/decode via EncryptText/DecryptText 138 | ClassMethod GetKey() [ CodeMode = expression ] 139 | { 140 | $Get(^Arduino("Key")) 141 | } 142 | 143 | /// Get IV to encode/decode via EncryptText/DecryptText 144 | ClassMethod GetIV() [ CodeMode = expression ] 145 | { 146 | $Get(^Arduino("IV")) 147 | } 148 | 149 | /// Encrypt PlainText with AESCBCEncrypt 150 | /// Write ##class(Arduino.Delegated).EncryptText("string") 151 | ClassMethod EncryptText(PlainText As %String) As %String 152 | { 153 | 154 | Set Text=$ZConvert(PlainText,"O","UTF8") 155 | Set Text=$System.Encryption.AESCBCEncrypt(Text, ..GetKey(), ..GetIV()) 156 | Set Ciphertext=$System.Encryption.Base64Encode(Text) 157 | Return Ciphertext 158 | } 159 | 160 | /// Decrypt PlainText with AESCBCEncrypt 161 | /// Write ##class(Arduino.Delegated).DecryptText("sFgKzZVle187N4OqhhcXPw==") 162 | ClassMethod DecryptText(CipherText As %String) As %String 163 | { 164 | Set Text=$System.Encryption.Base64Decode(CipherText) 165 | Set Text=$System.Encryption.AESCBCDecrypt(Text, ..GetKey(), ..GetIV()) 166 | Set PlainText=$ZConvert(Text,"I","UTF8") 167 | Return PlainText 168 | } 169 | 170 | /// Extends right side of a String by Character up to Length chars 171 | /// Write ##class(Arduino.Delegated).AppendToString("") 172 | ClassMethod AppendToString(String As %String, Character As %String(MAXLEN=1) = "_", Length As %Integer = {$Length(String)}) As %String 173 | { 174 | Set Difference = Length - $Length(String) 175 | Return:Difference<=0 String 176 | Set Tail = $Justify("", Difference) 177 | Set Tail = $Translate(Tail, " ", Character) 178 | Return String _ Tail 179 | } 180 | 181 | } 182 | 183 | --------------------------------------------------------------------------------