2021. december 22., szerda

Dimag - PowerShell

Remélem ezért nem leszek keresztre feszítve.

Szóval: Használom a Dimag-ot, előfizetéses elektronikus újságok olvasására, de nem szeretem. Az alkalmazás is a hozzáállás is csapnivaló.

Szeretem, ha az éveken évtizedeken keresztül olvasott szaklapok megvannak a gépemen pdf-ben. Ez amolyan gyűjtőszenvedély féle (biztos orvoshoz kéne fordulnom).

Persze a Dimag-ból kiszedni a dolgokat nem igazán lehet. Elvégre arra szántak rengeteg energiát, hogy a holnapi napot is titkosítsák, arra meg nullát, hogy egy értelmezhető felhasználói élményt nyújtsanak.

Arra jutottam, hogy képernyőfotóként lementem az oldalakat, majd ebből csinálok pdf-et.

Ennek az első része mechanikus, igényel némi rendszeres precizitást. Szóval:

  • Dimag Chrome-ban megnyit.
  • Bal oldali oldalankénti navigáció kikapcsol
  • Teljes képernyőre kirak (F11)

Így minden oldal, minden esetben ugyanoda kerül a képernyőn (az egyes oldalak középre, az oldalpárok két oldalra). A képeket egyes oldalnál <oldalszám>.jpg, oldalpárnál <páros oldal>-<páratlan oldal>.jpg néven mentem. Minden oldalszám szigorúan három számjegy.

Na eddig van a mechanikus munka (még gondolkozom, tudom-e tovább automatizálni). A lementett jpeg-ekre megy ez a PowerShell + ImageMagick script, és már kész is a friss ropogós pdf:

$srcfiles = Get-ChildItem "./*.jpg" | Sort-Object -Property Name
$dstlist = ''
foreach($jpg in $srcfiles) {
    if($jpg.Name -match '[0-9]{3}-[0-9]{3}\.jpg') {
        magick $jpg.Name -crop '1483x2081+436+7' "p$($jpg.Name.Substring(0,3)).jpg"
        $dstlist += "p" + $jpg.Name.Substring(0,3) + ".jpg "
        magick $jpg.Name -crop '1483x2081+1920+7' "p$($jpg.Name.Substring(4,3)).jpg"
        $dstlist += "p" + $jpg.Name.Substring(4,3) + ".jpg "
    }
    else {
        if($jpg.Name -match '[0-9]{3}\.jpg') {
            magick $jpg.Name -crop '1483x2081+1178+7' "p$($jpg.Name.Substring(0,3)).jpg"
            $dstlist += "p" + $jpg.Name.Substring(0,3) + ".jpg "
        }
    }
}
$dstlist += "result.pdf"
Start-Process -NoNewWindow -FilePath "magick.exe" -ArgumentList $dstlist -Wait
Remove-Item p*.jpg

A fenti kód az én 4K monitorommal működik. Más monitorhoz át kell írni a méreteket.

Továbbá:

  • Nem árulom el, melyik magazinnál használom.
  • A saját infrastruktúrám az elkészült pdf-ek nem hagyják el.
  • Amivel dolgozom, azt előfizettem, nincs benne semmi hack


Műszervezérlés - irányok

 

A dolgok változnak.

Amikor újrakezdtem a műszervezérlő projectemet, világos volt az irány előttem. Majd rájöttem pár dologra, ami arra késztetett, hogy újragondoljam a projectet, és hogy az egészet én hogyan látom.

Először is, ezt találtam: https://github.com/xyphro/UsbGpib

Ez pontosan az amire szükségem van. 90%-ban biztos vagyok, hogy a firmware amit fejlesztettem a saját panelemhez szükségtelen (meglepetések persze érhetnek, amikor ezt a saját panelemre a és a szoftverkörnyezetemhez próbálom adaptálni, de ennek kicsi az esélye).

A vezérlő szoftverembe bekerült egy plusz réteg a VISA fölé (alapvetően a soros-GPIB megoldásom miatt). Gondolkodtam rajta, hogy ez esetleg most kidobható lenne, de rájöttem, hogy vannak eszközök amik HID-t, vagy saját protokolt használnak, amiket nem tudok a VISA esernyő alá begyömöszölni.

Van egy nagy dilemmám a további fejlesztéssel kapcsolatban. A desktop műszervezérlő alkalmazásra gondolok itt.

A helyzet:

Ma a szoftver fejlesztés világában minden a mobilról a webről és a felhőről szól. Teljesen tiszta, hogy a világ ebbe az irányba halad. Még én is DevOps szakiként, felhő alapú web projecteken dolgozom, már jó pár éve.

De...

Mindig az a zavaró "de".

De a műszervezérlés világa, egy kicsit különbözik. Amit látok, érzek a műszer vezérlő és megjelenítő szoftverekről, hogy elsősorban nem web technológiák köré épültek. Ezek, változatlanul desktop alkalmazások. Én ezt nem akarom megváltoztatni. Kényelmesebb ezeket így használni, egyszerűbb közvetlenül kommunikálni a hardverrel, stb.

A saját szoftverem C#-ban kezdtem el fejleszteni .NET Framework-ön Visual Studioban, WinForms-al. Ez az a platform, amiben a legtöbb saját tapasztalatom van. Ha megtartom a lusta hozzáállásom, csak egyszerűen folytatom ezt és elfelejtem a dilemmám. Alapvetően magamnak fejlesztek, így nem igazán kell törődnöm ezzel.

De valami állandóan viszket a fejemben. A fenti technológia kezd túlhaladott lenni. A saját projectjeimet (a feladat megoldása mellett) tanulásra is használom. Szóval a kérdés: Milyen irányba menjek?

A másik dolog ami izgat ebben, a Linux. Kéne egy több platformon futó eszközt írnom? Saját magamnak, nem feltétlenül. Ha más is akarja használni ezt, akkor ez szükségessé válhat.

A lehetőségek, amiket látok:

  • Tartsam ezt meg, folytassam a fejlesztést és csak felejtsem el a dilemmám?
  • Költöztessem át a .NET 6, WPF, MVVM megoldásra, hogy újabb platformom legyen? Ez még mindige nem jelent Linux platformot, csak remélhetem, hogy valaki csinál egy használható verziót a MAUI-ból Linuxra.
  • Költözzek át .NET 6-ra és használjak valami harmadik gyártó UI-t (Avalonia, UNO Platform, QT, vagy más)?
  • Felejtsem el az egész C# és .NET vonalat és használjak mást?
    • A Python-hoz van a PyVISA műszervezérló könyvtár. Nem igazán szeretem a Python-t és még mindig kell találnom valami UI-t.
    • A Java-hoz vannak desktop framework-ök, de mi lesz a műszerekkel?
    • A Node.js-hez ott az Electron, de a VISA-t támogató könyvtárak minősége, eléggé kérdőjeles.
    • Bármi más ami nem jutott eszembe?

Próbáltam összegyűjteni (legalább részben) a követelményeket:

  • Natív desktop alkalmazás
  • Hardver kommunikáció (Soros, USB-HID, IVI réteg, mint a Keysight IO Library Suite, USB-TMC, stb.)
  • Grafikai elemek - Dialógus ablakok, Data grid, szöveg mezők/vezérlők, és ami a legfontosabb, diagrammok.
  • Valami plug-in architektúra (plugin kell a műszerekhez, kommunikációs platformokhoz, stb. - az egésznek bővíthetőnek kell maradnia)
  • Hálózat kezelés
  • Fájl rendszer kezelés
Biztos van még más is. Egyenlőre ezeket látom.

Szóval, ha vannak gondolataid erről, kérlek oszd meg velem!

2021. december 5., vasárnap

USB-GPIB csatoló V2.1

 

Ez egy némi javítás, hibakezelés a korábbi ATMEGA32U4 alapú USB-GPIB csatolómhoz. Az előzőnek volt néhány baja. Ütközött a bootloader LED-jeinek a konfigurációja a GPIB jelekkel. Teljesen újradefiniáltam az eredeti Arduino jelekhez képest, hogy ki tudjam használni az interrupt kezelést. Továbbá egy teljes 8 bites portot használtam adatbuszként, hogy egyben írható/olvasható legyen és ne bitenként.

Az új verzióban kicsit más lett a megközelítés:

  • Próbáltam az Arduino Leonardo lábkonfigurációjánál maradni, amennyire tudtam.
  • Feladtam az interrupt kezelést az SRQ vonalat leszámítva
  • Megtartottam a 8 bit adatbuszt
  • Konfigurálhatóvá tettem - lehet választani az AR488 által használt konfiguráció és a fenti 8 bites egybe adatbusz között (az AR488 verziónak nem kell speciális bootloader)
  • Megtartottam az állapot LEDeket
  • Hozzáadtam egy hibakeresésre használható soros portot

Később ez a terv lesz az alapja a teljes GPIB csatolónak, megfelelő vonalmeghajtókkal együtt. Ez a verzió, csak egy műszer vezérlésére használható (lehet, bírna többet is, de inkább nem próbálom ki). 

A kapcsolási rajz:

A nyák terv:


A robbantott 3D model:


Igen tudom, hogy a csatlakozó neme, nem a megfelelő (bár ki tudja ma már, hogy mi a megfelelő nem), de sajnos nem találtam megfelelő 3D modellt, és annyira nem volt fontos, annyi volt a lényeg, hogy reprezentálja a megfelelő méretet a 3D modell tervezéshez.
A teljes terv itt található:
Ezzel az a témában elkészült új tervek száma kettőre emelkedett, szóval itt az ideje, hogy megrendeljem a paneleket.


2021. december 3., péntek

Új műhely

Végre hivatalos. Nagy harc volt a helyi önkormányzat bürokráciájával, hogy ezt sikerüljön elérni. Van egy új műhelyem. Még rengeteg pénz és munka lesz vele, amíg be tudok költözni (jópár hónapra számítok).




2021. november 30., kedd

USB-RS232 Csatoló

 

A műszervezérlés tervem megvalósításaként, először megterveztem az USB-RS232 csatolómat. Lehet, hogy ez még nem az utolsó verziója, de egyenlőre végeztem a tervezési fázissal.

A szerkezet a CH340G chipen alapul, amit korábban az ESP8266-os programozómon is sikeresen használtam, ugyanez van egy rakás kínai USB-Soros kábelben, Arduino-kban, 3D nyomtató vezérlőkben. Sosem volt semmi bajom ezekkel az eszközökkel. A megfelelő jelszintek előállítására hozzáadtam még egy MAX232-es tokot.

Valószínüleg ez a megoldás nem optimális, miután nincs meg rajta az összes RS232 jel, de azt hiszem, egyenlőre jó lesz így (nem igazán akarok most több energiát belerakni ebbe).

A kapcsolási rajz:


A nyák terv:


Esetleg észreveheted a kapcsolási rajzon és a nyák terven, hogy "kettős" USB csatlakozás van rajta. Ez azt jelenti, hogy az USB jelek mind egy mikro USB csatlakozón, mind pár forszemen elérhetőek. Ez a megoldás azt a lehetőséget kínálja, hogy akár USB csatlakozóval, akár kábellel szereljük össze az eszközt.
Ennek a koncepciónak megfelelően két különböző dobozkát terveztem hozzá.
USB csatlakozóhoz:


Kábelhez:


Megfigyelhető, hogy a panel maga a 3D terven szürke. Az ok, hogy nem tudtam a színes 3D modellt beimportálni az OpenSCAD-be, amit a 3D modellezéshez használok (lehet, nem is tud ilyet).
Az eredeti 3D nézet, ilyen:


Jelenleg még nem akarom a panelt legyártani, mert a GPIB csatoló következő verzióján dolgozom és össze akarom montírozni egy panelre a gyártási költségek csökkentése miatt.

A tervek itt találhatóak:

Nekiálltam a mindenféle műszervezérlős dolgom átszervezésének is. A kapcsolódó repók itt lesznek majd elérhetőek:


2021. november 27., szombat

Műszervezérlés - újrakezdve

 

Bevezető

Az elmúlt években rengeteg munkát raktam a különböző műszereim számítógépes vezérlésébe. A terv az volt, hogy valami hozzáadott értéket teremtsek vele, úgy mint logolás, jobb láthatóság, több - integrált - funkció, stb.
Úgy néz ki, hogy ezzel kicsit megbuktam, miután semmi sem jutott el, a használhatósági állapotba.
Az egészet, hónapokkal ezelőtt félretettem. Most úgy érzem, ideje leporolnom és újrakezdenem, hogy valami "működő" állapotig eljussak vele.

Tervek

A forrás repók újraszervezése

Ez azért szükséges, mert rengeteg dolgot tanultam az elmúlt években a munkám kapcsán a gitről (branch stratégiák, release kezelés, etc.)

USB-RS232 interfész tervezés

Van egy pár eszközöm ami RS232 interfésszel rendelkezik a GPIB helyett/mellett. Igen, vehetsz USB-Soros átalakítót gombokért. Miért kell egy másik? A legtöbb darab amit kapsz, nem tudja a megfelelő jelszinteket. TTL szintet használnak RS232 helyett. A legtöbb professzionális műszernek szüksége van a megfelelő jelszintekre. A megfelelő csatoló nem olcsó, vagy azt kockáztatod, hogy veszel valami vackot az Aliexpressen ami azt állítja magáról, hogy megfelelő, közben nem.

USB-GPIB hardver újratervezése

Az ATMEGA32U4 alapú interfészem tökéletesem működik. Az elmúlt években ugyanakkor kiderült pár dolog ami arra késztet, hogy szükség van pár módosításra:
  • Olyan fizikai terv kialakítása, hogy 3D nyomtatott dobozba lehessen tenni.
  • Elhagyni azokat a csatlakozókat amiket későbbi továbbfejlesztésre terveztem bele mint kijelző plusz eszközök vezérlése, stb.
  • Soros debug lehetőség (az AR488-nak megfelelően)
  • Az Arduino Leonardo bootloaderrel való kompatibilitás
  • Megtartani a teljes 8bites buszból adódó adat transzfer előnyöket (módosított bootloader szükséges)
  • Az AR488 szoftverrel való kompatibilitás megtartása (https://github.com/Twilight-Logic/AR488)
  • Aktivitás LED-ek hozzáadása (az eredeti Arduino Leonardo-nak megfelelően)
  • Teljes GPIB meghajtó TI ICkkel (másik hardver verzió szükséges)
Az AR488 kompatibilitás megtartása nem jelenti azt, hogy a saját firmware-emet ki tervezném dobni. Változatlanul nem békéltem megy a 3000+ sor kóddal egyetlen forrásfájlban. Az AR488 még mindíg nem támogatja a GPIB másodlagos címzést. Van egy rakás eszközöm (VXI keretek, moduláris labortáp keret), amiknek szüksége van erre. A másik oldalon támogatja a device üzemmódot, a TI GPIB IC-it, amik az enyémből hiányoznak, továbbá megvan a szoftver támogatása olyan eszközökben mint a sigrok.

Proper bootloader for USB-GPIB

Csináltam egy bootloadert a v2.0-ás panelhez. Ez egy annak a mellényúlásnak az eredménye volt, hogy újrahasznosítottam az Arduino Leonardo USB visszajelző LEDjeit, ami megölte a GPIB kommunikációt. A problémát akkor megoldottam, de az eredménye egy rosszul dokumentált (https://it-pro-hu.blogspot.com/2020/04/gp-ib-5-v20-panel.html), nehezen reprodukálható állapot lett. Ráadásul ez kinyírja a LED-eket és nem áthelyezi más uC lábakra. Most létre akarok hozni egy karbantartható, újrafordítható, megfelelően telepíthető megoldást. Ezen túl szeretnék a szabályoknak megfelelő PID/VID páros kérni a pid.codes-tól.

Tápegység vezérlő szoftver

A virtuális műszer szoftverem sok dologra lenne alkalmas, de rájöttem, hogy túl magasra tettem a lécet, első nekifutásra. Sok mindent megcsináltam már benne, a jelenlegi újrakezdéshez kisebbet akarok fogni.
Tehát megtartva a cserélhető driver támogatást akarok csinálni egy tápegység vezérlő szoftvert a rengeteg tápegységemhez (ráadásul a HP 66000A moduláris tápegység nem is használható szoftver nélkül, mert nincs hozzá meg a saját billentyűzete). Ebbe egyenlőre nem akarom magasabb szintű funkciókat rakni.

Továbbiak...

Természetesen, nem akarok itt megállni, újra akarom indítani a virtuális műszer fejlesztésem, a karakterisztika rajzolót, stb.
Ezek a dolgok egyenlőre homályosak, és ha elveszítem a fókuszt ezem megint, annak csak egy polcra rakott project hegy lesz az eredménye. Megint.

2021. november 11., csütörtök

Terraform, Cloudformation és Cognito

Némi IT és némi felhő újra

IaC eszközökkel dolgozom már nem is igazán tudom mióta. Az AWS CloudFormation-nel kezdtem valamikor 2014 körül (nem biztos, ez a ködös múltba vész)


Amikor elkezdtem a Terraformról tanulni, bennem volt a félelem, hogy nem fogok teljes AWS funkcionalitást kapni. A CloudFormation natív AWS eszköz. Valami amit egy külső gyártó fejleszt - elméletben - csak követheti a szolgáltató natív eszközét.

Elkezdtem Terraformot használni, mert ez volt az ügyfél elvárása, tehát a váltás nem az én döntésem volt. A fenti félelmem akkor vált kicsit valósággá amikor az ügyfél nem követte az AWS Provider verzióit megfelelően a saját deployment agent-jein (tehát ez nem róható fel sem a HashiCorpnak, sem a Terraform közösségnek). Tehát tulajdonképpen nem látszott valós lemaradás a Terraform oldalán. Emellett Terraform kódot írni sokkal kényelmesebb, sokkal több lehetőséget nyújt amikor feldolgozni, konvertálni kell, a rendelkezésre álló információt.

Egy pár hete, kb. három év kizárólagos Terraform munka után belecsöppentem újra egy CloudFormation projectbe.

Van egy - azt hittem - szuper egyszerű feladat. Publikálni egy Cognito User Pool Client titkos kulcsot az SSM Parameter Store-ba, titkosítva.

Terraformban ez így néz ki:

// Create Cognito User Pool
resource "aws_cognito_user_pool" "pool" {
  name = "pool"
}

// Create Cognito User Pool Client
resource "aws_cognito_user_pool_client" "client" {
  name = "client"
  user_pool_id = aws_cognito_user_pool.pool.id
  generate_secret     = true
}

// Publish to SSM Parameter Store
resource "aws_ssm_parameter" "secret" {
  name        = "/production/cognito/clientSecret"
  type        = "SecureString"
  value       = ${aws_cognito_user_pool_client.client.client_secret}
}

És kész is vagyunk.

Próbáljuk meg ugyanezt a CloudFormation-ben.

Vajon a AWS::Cognito::UserPoolClient objektum, ki tudja-e exportálni a titkos kulcsot? Nem. Forrás: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cognito-userpoolclient.html

Vajon a AWS::SSM::Parameter objektum tud-e SecureString értéket létrehozni? Nem. Forrás: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ssm-parameter.html

Itt van ahol a fenti teóriám "A CloudFormation-nek előrébb kell járnia mint a Terraformnak" megbukik.

Sok mindennel próbálkoztam sikertelenül, hogy megoldjam ezt. Végülis a következő kódrészlet működött (egy megjegyzés: a Python kódban, az import cfnresponse nem az én trehányságom miatt van külön sorban. Ez kell az AWS lambdának, hogy észrevegye, kell neki a cfnresponse.py és belerakja a deployment során a zip fájlba, ugyanis nem része a pip repónak):

Resources:
  # Create Cognito User Pool
  UserPool:
    Type: "AWS::Cognito::UserPool"
    Properties:
      UserPoolName: pool

  # Create Cognito User Pool Client
  UserPoolClient:
    Type: "AWS::Cognito::UserPoolClient"
    Properties:
      AccessTokenValidity: 15
      AllowedOAuthFlowsUserPoolClient: false
      ClientName: client
      GenerateSecret: true

  # You need a lambda to
  #     - read from the cognito user pool client
  #     - write to the parameter store
  #     - report back to the CloudFormation when finished
  CognitoSecretExporterLambda:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: CognitoSecretExporter
      Runtime: python3.9
      Role: !GetAtt CognitoSecretExporterExecutionRole.Arn
      Handler: index.handler
      Timeout: 30
      Environment:
        Variables:
          CognitoUserPoolId: !Ref UserPool
          CognitoUserPoolClientId: !Ref UserPoolClient
          ssmParameterName: /production/cognito/ClientSecret
      Code:
        ZipFile: |
          import boto3, os
          import cfnresponse

          def handler(event, context):
              CognitoUserPoolId = os.environ['CognitoUserPoolId']
              CognitoUserPoolClientId = os.environ['CognitoUserPoolClientId']
              ssmParameterName = os.environ['ssmParameterName']

              # Read Cognito
              cognito = boto3.client('cognito-idp')
              response = cognito.describe_user_pool_client(
                  UserPoolId = CognitoUserPoolId,
                  ClientId = CognitoUserPoolClientId
              )
              cognitoClientSecret = response['UserPoolClient']['ClientSecret']
              print(cognitoClientSecret)
              ssm = boto3.client('ssm')

              # Write to parameter store
              response = ssm.put_parameter(
                  Name = ssmParameterName,
                  Description = '[CF] Cognito Client Secret used by the WebApp',
                  Value = cognitoClientSecret,
                  Type = 'SecureString',
                  KeyId = 'alias/aws/ssm',
                  Overwrite = True,
                  Tier='Standard'
              )

              # Report success to CloudFormation
              responseData = {}
              responseData['Data'] = 120
              cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData) 

  # Trigger the lambda from the CloudFormation stack
  CognitoSecretExporterInvoke:
    Type: AWS::CloudFormation::CustomResource
    DependsOn: CognitoSecretExporterLambda
    Version: "1.0"
    Properties:
      ServiceToken: !GetAtt CognitoSecretExporterLambda.Arn 

  # IAM Role for the lambda above
  CognitoSecretExporterExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: CognitoSecretExporterExecutionRole
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
              - lambda.amazonaws.com
          Action:
            - sts:AssumeRole
      Path: "/"
      Policies:
      - PolicyName: root
      PolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Sid: EnablePutLogEvents
              Effect: Allow
              Action:
                - logs:CreateLogGroup
                - logs:CreateLogStream
                - logs:PutLogEvents
              Resource:
                - '*'
            - Sid: ReadCognito
              Effect: Allow
              Action:
                - cognito-idp:DescribeUserPoolClient
              Resource:
                - !GetAtt UserPool.Arn
            - Sid: ParamStore
              Effect: Allow
              Action:
                - ssm:DeleteParameter
                - ssm:PutParameter
                - ssm:GetParameter
              Resource: 
                - !Sub arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/production/cognito/ClientSecret